##// END OF EJS Templates
database: dropped CheckConstraint for auto-increment field for mysql/mariadb compatability....
marcink -
r3486:118155b6 default
parent child Browse files
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -1,1044 +1,1044 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2019 RhodeCode GmbH
3 # Copyright (C) 2010-2019 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import os
21 import os
22 import logging
22 import logging
23 import datetime
23 import datetime
24 import traceback
24 import traceback
25 from datetime import date
25 from datetime import date
26
26
27 from sqlalchemy import *
27 from sqlalchemy import *
28 from sqlalchemy.ext.hybrid import hybrid_property
28 from sqlalchemy.ext.hybrid import hybrid_property
29 from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
29 from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
30 from beaker.cache import cache_region, region_invalidate
30 from beaker.cache import cache_region, region_invalidate
31 from pyramid import compat
31 from pyramid import compat
32
32
33 from rhodecode.lib.vcs import get_backend
33 from rhodecode.lib.vcs import get_backend
34 from rhodecode.lib.vcs.utils.helpers import get_scm
34 from rhodecode.lib.vcs.utils.helpers import get_scm
35 from rhodecode.lib.vcs.exceptions import VCSError
35 from rhodecode.lib.vcs.exceptions import VCSError
36 from zope.cachedescriptors.property import Lazy as LazyProperty
36 from zope.cachedescriptors.property import Lazy as LazyProperty
37 from rhodecode.lib.auth import generate_auth_token
37 from rhodecode.lib.auth import generate_auth_token
38 from rhodecode.lib.utils2 import str2bool, safe_str, get_commit_safe, safe_unicode
38 from rhodecode.lib.utils2 import str2bool, safe_str, get_commit_safe, safe_unicode
39 from rhodecode.lib.exceptions import UserGroupAssignedException
39 from rhodecode.lib.exceptions import UserGroupAssignedException
40 from rhodecode.lib.ext_json import json
40 from rhodecode.lib.ext_json import json
41
41
42 from rhodecode.model.meta import Base, Session
42 from rhodecode.model.meta import Base, Session
43 from rhodecode.lib.caching_query import FromCache
43 from rhodecode.lib.caching_query import FromCache
44
44
45
45
46 log = logging.getLogger(__name__)
46 log = logging.getLogger(__name__)
47
47
48 #==============================================================================
48 #==============================================================================
49 # BASE CLASSES
49 # BASE CLASSES
50 #==============================================================================
50 #==============================================================================
51
51
52 class ModelSerializer(json.JSONEncoder):
52 class ModelSerializer(json.JSONEncoder):
53 """
53 """
54 Simple Serializer for JSON,
54 Simple Serializer for JSON,
55
55
56 usage::
56 usage::
57
57
58 to make object customized for serialization implement a __json__
58 to make object customized for serialization implement a __json__
59 method that will return a dict for serialization into json
59 method that will return a dict for serialization into json
60
60
61 example::
61 example::
62
62
63 class Task(object):
63 class Task(object):
64
64
65 def __init__(self, name, value):
65 def __init__(self, name, value):
66 self.name = name
66 self.name = name
67 self.value = value
67 self.value = value
68
68
69 def __json__(self):
69 def __json__(self):
70 return dict(name=self.name,
70 return dict(name=self.name,
71 value=self.value)
71 value=self.value)
72
72
73 """
73 """
74
74
75 def default(self, obj):
75 def default(self, obj):
76
76
77 if hasattr(obj, '__json__'):
77 if hasattr(obj, '__json__'):
78 return obj.__json__()
78 return obj.__json__()
79 else:
79 else:
80 return json.JSONEncoder.default(self, obj)
80 return json.JSONEncoder.default(self, obj)
81
81
82 class BaseModel(object):
82 class BaseModel(object):
83 """Base Model for all classess
83 """Base Model for all classess
84
84
85 """
85 """
86
86
87 @classmethod
87 @classmethod
88 def _get_keys(cls):
88 def _get_keys(cls):
89 """return column names for this model """
89 """return column names for this model """
90 return class_mapper(cls).c.keys()
90 return class_mapper(cls).c.keys()
91
91
92 def get_dict(self):
92 def get_dict(self):
93 """return dict with keys and values corresponding
93 """return dict with keys and values corresponding
94 to this model data """
94 to this model data """
95
95
96 d = {}
96 d = {}
97 for k in self._get_keys():
97 for k in self._get_keys():
98 d[k] = getattr(self, k)
98 d[k] = getattr(self, k)
99 return d
99 return d
100
100
101 def get_appstruct(self):
101 def get_appstruct(self):
102 """return list with keys and values tupples corresponding
102 """return list with keys and values tupples corresponding
103 to this model data """
103 to this model data """
104
104
105 l = []
105 l = []
106 for k in self._get_keys():
106 for k in self._get_keys():
107 l.append((k, getattr(self, k),))
107 l.append((k, getattr(self, k),))
108 return l
108 return l
109
109
110 def populate_obj(self, populate_dict):
110 def populate_obj(self, populate_dict):
111 """populate model with data from given populate_dict"""
111 """populate model with data from given populate_dict"""
112
112
113 for k in self._get_keys():
113 for k in self._get_keys():
114 if k in populate_dict:
114 if k in populate_dict:
115 setattr(self, k, populate_dict[k])
115 setattr(self, k, populate_dict[k])
116
116
117 @classmethod
117 @classmethod
118 def query(cls):
118 def query(cls):
119 return Session.query(cls)
119 return Session.query(cls)
120
120
121 @classmethod
121 @classmethod
122 def get(cls, id_):
122 def get(cls, id_):
123 if id_:
123 if id_:
124 return cls.query().get(id_)
124 return cls.query().get(id_)
125
125
126 @classmethod
126 @classmethod
127 def getAll(cls):
127 def getAll(cls):
128 return cls.query().all()
128 return cls.query().all()
129
129
130 @classmethod
130 @classmethod
131 def delete(cls, id_):
131 def delete(cls, id_):
132 obj = cls.query().get(id_)
132 obj = cls.query().get(id_)
133 Session.delete(obj)
133 Session.delete(obj)
134 Session.commit()
134 Session.commit()
135
135
136
136
137 class RhodeCodeSetting(Base, BaseModel):
137 class RhodeCodeSetting(Base, BaseModel):
138 __tablename__ = 'rhodecode_settings'
138 __tablename__ = 'rhodecode_settings'
139 __table_args__ = (UniqueConstraint('app_settings_name'), {'extend_existing':True})
139 __table_args__ = (UniqueConstraint('app_settings_name'), {'extend_existing':True})
140 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
140 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
141 app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None)
141 app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None)
142 _app_settings_value = Column("app_settings_value", String(255), nullable=True, unique=None, default=None)
142 _app_settings_value = Column("app_settings_value", String(255), nullable=True, unique=None, default=None)
143
143
144 def __init__(self, k='', v=''):
144 def __init__(self, k='', v=''):
145 self.app_settings_name = k
145 self.app_settings_name = k
146 self.app_settings_value = v
146 self.app_settings_value = v
147
147
148
148
149 @validates('_app_settings_value')
149 @validates('_app_settings_value')
150 def validate_settings_value(self, key, val):
150 def validate_settings_value(self, key, val):
151 assert type(val) == unicode
151 assert type(val) == unicode
152 return val
152 return val
153
153
154 @hybrid_property
154 @hybrid_property
155 def app_settings_value(self):
155 def app_settings_value(self):
156 v = self._app_settings_value
156 v = self._app_settings_value
157 if v == 'ldap_active':
157 if v == 'ldap_active':
158 v = str2bool(v)
158 v = str2bool(v)
159 return v
159 return v
160
160
161 @app_settings_value.setter
161 @app_settings_value.setter
162 def app_settings_value(self, val):
162 def app_settings_value(self, val):
163 """
163 """
164 Setter that will always make sure we use unicode in app_settings_value
164 Setter that will always make sure we use unicode in app_settings_value
165
165
166 :param val:
166 :param val:
167 """
167 """
168 self._app_settings_value = safe_unicode(val)
168 self._app_settings_value = safe_unicode(val)
169
169
170 def __repr__(self):
170 def __repr__(self):
171 return "<%s('%s:%s')>" % (self.__class__.__name__,
171 return "<%s('%s:%s')>" % (self.__class__.__name__,
172 self.app_settings_name, self.app_settings_value)
172 self.app_settings_name, self.app_settings_value)
173
173
174
174
175 @classmethod
175 @classmethod
176 def get_by_name(cls, ldap_key):
176 def get_by_name(cls, ldap_key):
177 return cls.query()\
177 return cls.query()\
178 .filter(cls.app_settings_name == ldap_key).scalar()
178 .filter(cls.app_settings_name == ldap_key).scalar()
179
179
180 @classmethod
180 @classmethod
181 def get_app_settings(cls, cache=False):
181 def get_app_settings(cls, cache=False):
182
182
183 ret = cls.query()
183 ret = cls.query()
184
184
185 if cache:
185 if cache:
186 ret = ret.options(FromCache("sql_cache_short", "get_hg_settings"))
186 ret = ret.options(FromCache("sql_cache_short", "get_hg_settings"))
187
187
188 if not ret:
188 if not ret:
189 raise Exception('Could not get application settings !')
189 raise Exception('Could not get application settings !')
190 settings = {}
190 settings = {}
191 for each in ret:
191 for each in ret:
192 settings['rhodecode_' + each.app_settings_name] = \
192 settings['rhodecode_' + each.app_settings_name] = \
193 each.app_settings_value
193 each.app_settings_value
194
194
195 return settings
195 return settings
196
196
197 @classmethod
197 @classmethod
198 def get_ldap_settings(cls, cache=False):
198 def get_ldap_settings(cls, cache=False):
199 ret = cls.query()\
199 ret = cls.query()\
200 .filter(cls.app_settings_name.startswith('ldap_')).all()
200 .filter(cls.app_settings_name.startswith('ldap_')).all()
201 fd = {}
201 fd = {}
202 for row in ret:
202 for row in ret:
203 fd.update({row.app_settings_name:row.app_settings_value})
203 fd.update({row.app_settings_name:row.app_settings_value})
204
204
205 return fd
205 return fd
206
206
207
207
208 class RhodeCodeUi(Base, BaseModel):
208 class RhodeCodeUi(Base, BaseModel):
209 __tablename__ = 'rhodecode_ui'
209 __tablename__ = 'rhodecode_ui'
210 __table_args__ = (UniqueConstraint('ui_key'), {'extend_existing':True})
210 __table_args__ = (UniqueConstraint('ui_key'), {'extend_existing':True})
211
211
212 HOOK_REPO_SIZE = 'changegroup.repo_size'
212 HOOK_REPO_SIZE = 'changegroup.repo_size'
213 HOOK_PUSH = 'pretxnchangegroup.push_logger'
213 HOOK_PUSH = 'pretxnchangegroup.push_logger'
214 HOOK_PULL = 'preoutgoing.pull_logger'
214 HOOK_PULL = 'preoutgoing.pull_logger'
215
215
216 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
216 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
217 ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None)
217 ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None)
218 ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None)
218 ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None)
219 ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None)
219 ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None)
220 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
220 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
221
221
222
222
223 @classmethod
223 @classmethod
224 def get_by_key(cls, key):
224 def get_by_key(cls, key):
225 return cls.query().filter(cls.ui_key == key)
225 return cls.query().filter(cls.ui_key == key)
226
226
227
227
228 @classmethod
228 @classmethod
229 def get_builtin_hooks(cls):
229 def get_builtin_hooks(cls):
230 q = cls.query()
230 q = cls.query()
231 q = q.filter(cls.ui_key.in_([cls.HOOK_REPO_SIZE,
231 q = q.filter(cls.ui_key.in_([cls.HOOK_REPO_SIZE,
232 cls.HOOK_PUSH, cls.HOOK_PULL]))
232 cls.HOOK_PUSH, cls.HOOK_PULL]))
233 return q.all()
233 return q.all()
234
234
235 @classmethod
235 @classmethod
236 def get_custom_hooks(cls):
236 def get_custom_hooks(cls):
237 q = cls.query()
237 q = cls.query()
238 q = q.filter(~cls.ui_key.in_([cls.HOOK_REPO_SIZE,
238 q = q.filter(~cls.ui_key.in_([cls.HOOK_REPO_SIZE,
239 cls.HOOK_PUSH, cls.HOOK_PULL]))
239 cls.HOOK_PUSH, cls.HOOK_PULL]))
240 q = q.filter(cls.ui_section == 'hooks')
240 q = q.filter(cls.ui_section == 'hooks')
241 return q.all()
241 return q.all()
242
242
243 @classmethod
243 @classmethod
244 def create_or_update_hook(cls, key, val):
244 def create_or_update_hook(cls, key, val):
245 new_ui = cls.get_by_key(key).scalar() or cls()
245 new_ui = cls.get_by_key(key).scalar() or cls()
246 new_ui.ui_section = 'hooks'
246 new_ui.ui_section = 'hooks'
247 new_ui.ui_active = True
247 new_ui.ui_active = True
248 new_ui.ui_key = key
248 new_ui.ui_key = key
249 new_ui.ui_value = val
249 new_ui.ui_value = val
250
250
251 Session.add(new_ui)
251 Session.add(new_ui)
252 Session.commit()
252 Session.commit()
253
253
254
254
255 class User(Base, BaseModel):
255 class User(Base, BaseModel):
256 __tablename__ = 'users'
256 __tablename__ = 'users'
257 __table_args__ = (UniqueConstraint('username'), UniqueConstraint('email'), {'extend_existing':True})
257 __table_args__ = (UniqueConstraint('username'), UniqueConstraint('email'), {'extend_existing':True})
258 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
258 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
259 username = Column("username", String(255), nullable=True, unique=None, default=None)
259 username = Column("username", String(255), nullable=True, unique=None, default=None)
260 password = Column("password", String(255), nullable=True, unique=None, default=None)
260 password = Column("password", String(255), nullable=True, unique=None, default=None)
261 active = Column("active", Boolean(), nullable=True, unique=None, default=None)
261 active = Column("active", Boolean(), nullable=True, unique=None, default=None)
262 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
262 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
263 name = Column("name", String(255), nullable=True, unique=None, default=None)
263 name = Column("name", String(255), nullable=True, unique=None, default=None)
264 lastname = Column("lastname", String(255), nullable=True, unique=None, default=None)
264 lastname = Column("lastname", String(255), nullable=True, unique=None, default=None)
265 email = Column("email", String(255), nullable=True, unique=None, default=None)
265 email = Column("email", String(255), nullable=True, unique=None, default=None)
266 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
266 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
267 ldap_dn = Column("ldap_dn", String(255), nullable=True, unique=None, default=None)
267 ldap_dn = Column("ldap_dn", String(255), nullable=True, unique=None, default=None)
268 api_key = Column("api_key", String(255), nullable=True, unique=None, default=None)
268 api_key = Column("api_key", String(255), nullable=True, unique=None, default=None)
269
269
270 user_log = relationship('UserLog', cascade='all')
270 user_log = relationship('UserLog', cascade='all')
271 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
271 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
272
272
273 repositories = relationship('Repository')
273 repositories = relationship('Repository')
274 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
274 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
275 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
275 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
276
276
277 group_member = relationship('UserGroupMember', cascade='all')
277 group_member = relationship('UserGroupMember', cascade='all')
278
278
279 @property
279 @property
280 def full_contact(self):
280 def full_contact(self):
281 return '%s %s <%s>' % (self.name, self.lastname, self.email)
281 return '%s %s <%s>' % (self.name, self.lastname, self.email)
282
282
283 @property
283 @property
284 def short_contact(self):
284 def short_contact(self):
285 return '%s %s' % (self.name, self.lastname)
285 return '%s %s' % (self.name, self.lastname)
286
286
287 @property
287 @property
288 def is_admin(self):
288 def is_admin(self):
289 return self.admin
289 return self.admin
290
290
291 def __repr__(self):
291 def __repr__(self):
292 try:
292 try:
293 return "<%s('id:%s:%s')>" % (self.__class__.__name__,
293 return "<%s('id:%s:%s')>" % (self.__class__.__name__,
294 self.user_id, self.username)
294 self.user_id, self.username)
295 except:
295 except:
296 return self.__class__.__name__
296 return self.__class__.__name__
297
297
298 @classmethod
298 @classmethod
299 def get_by_username(cls, username, case_insensitive=False):
299 def get_by_username(cls, username, case_insensitive=False):
300 if case_insensitive:
300 if case_insensitive:
301 return Session.query(cls).filter(cls.username.ilike(username)).scalar()
301 return Session.query(cls).filter(cls.username.ilike(username)).scalar()
302 else:
302 else:
303 return Session.query(cls).filter(cls.username == username).scalar()
303 return Session.query(cls).filter(cls.username == username).scalar()
304
304
305 @classmethod
305 @classmethod
306 def get_by_auth_token(cls, auth_token):
306 def get_by_auth_token(cls, auth_token):
307 return cls.query().filter(cls.api_key == auth_token).one()
307 return cls.query().filter(cls.api_key == auth_token).one()
308
308
309 def update_lastlogin(self):
309 def update_lastlogin(self):
310 """Update user lastlogin"""
310 """Update user lastlogin"""
311
311
312 self.last_login = datetime.datetime.now()
312 self.last_login = datetime.datetime.now()
313 Session.add(self)
313 Session.add(self)
314 Session.commit()
314 Session.commit()
315 log.debug('updated user %s lastlogin', self.username)
315 log.debug('updated user %s lastlogin', self.username)
316
316
317 @classmethod
317 @classmethod
318 def create(cls, form_data):
318 def create(cls, form_data):
319 from rhodecode.lib.auth import get_crypt_password
319 from rhodecode.lib.auth import get_crypt_password
320
320
321 try:
321 try:
322 new_user = cls()
322 new_user = cls()
323 for k, v in form_data.items():
323 for k, v in form_data.items():
324 if k == 'password':
324 if k == 'password':
325 v = get_crypt_password(v)
325 v = get_crypt_password(v)
326 setattr(new_user, k, v)
326 setattr(new_user, k, v)
327
327
328 new_user.api_key = generate_auth_token(form_data['username'])
328 new_user.api_key = generate_auth_token(form_data['username'])
329 Session.add(new_user)
329 Session.add(new_user)
330 Session.commit()
330 Session.commit()
331 return new_user
331 return new_user
332 except:
332 except:
333 log.error(traceback.format_exc())
333 log.error(traceback.format_exc())
334 Session.rollback()
334 Session.rollback()
335 raise
335 raise
336
336
337 class UserLog(Base, BaseModel):
337 class UserLog(Base, BaseModel):
338 __tablename__ = 'user_logs'
338 __tablename__ = 'user_logs'
339 __table_args__ = {'extend_existing':True}
339 __table_args__ = {'extend_existing':True}
340 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
340 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
341 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
341 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
342 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
342 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
343 repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None)
343 repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None)
344 user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None)
344 user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None)
345 action = Column("action", String(1200000), nullable=True, unique=None, default=None)
345 action = Column("action", String(1200000), nullable=True, unique=None, default=None)
346 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
346 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
347
347
348 @property
348 @property
349 def action_as_day(self):
349 def action_as_day(self):
350 return date(*self.action_date.timetuple()[:3])
350 return date(*self.action_date.timetuple()[:3])
351
351
352 user = relationship('User')
352 user = relationship('User')
353 repository = relationship('Repository')
353 repository = relationship('Repository')
354
354
355
355
356 class UserGroup(Base, BaseModel):
356 class UserGroup(Base, BaseModel):
357 __tablename__ = 'users_groups'
357 __tablename__ = 'users_groups'
358 __table_args__ = {'extend_existing':True}
358 __table_args__ = {'extend_existing':True}
359
359
360 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
360 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
361 users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None)
361 users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None)
362 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
362 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
363
363
364 members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
364 members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
365
365
366 def __repr__(self):
366 def __repr__(self):
367 return '<userGroup(%s)>' % (self.users_group_name)
367 return '<userGroup(%s)>' % (self.users_group_name)
368
368
369 @classmethod
369 @classmethod
370 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
370 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
371 if case_insensitive:
371 if case_insensitive:
372 gr = cls.query()\
372 gr = cls.query()\
373 .filter(cls.users_group_name.ilike(group_name))
373 .filter(cls.users_group_name.ilike(group_name))
374 else:
374 else:
375 gr = cls.query()\
375 gr = cls.query()\
376 .filter(cls.users_group_name == group_name)
376 .filter(cls.users_group_name == group_name)
377 if cache:
377 if cache:
378 gr = gr.options(FromCache("sql_cache_short",
378 gr = gr.options(FromCache("sql_cache_short",
379 "get_user_%s" % group_name))
379 "get_user_%s" % group_name))
380 return gr.scalar()
380 return gr.scalar()
381
381
382 @classmethod
382 @classmethod
383 def get(cls, users_group_id, cache=False):
383 def get(cls, users_group_id, cache=False):
384 users_group = cls.query()
384 users_group = cls.query()
385 if cache:
385 if cache:
386 users_group = users_group.options(FromCache("sql_cache_short",
386 users_group = users_group.options(FromCache("sql_cache_short",
387 "get_users_group_%s" % users_group_id))
387 "get_users_group_%s" % users_group_id))
388 return users_group.get(users_group_id)
388 return users_group.get(users_group_id)
389
389
390 @classmethod
390 @classmethod
391 def create(cls, form_data):
391 def create(cls, form_data):
392 try:
392 try:
393 new_user_group = cls()
393 new_user_group = cls()
394 for k, v in form_data.items():
394 for k, v in form_data.items():
395 setattr(new_user_group, k, v)
395 setattr(new_user_group, k, v)
396
396
397 Session.add(new_user_group)
397 Session.add(new_user_group)
398 Session.commit()
398 Session.commit()
399 return new_user_group
399 return new_user_group
400 except:
400 except:
401 log.error(traceback.format_exc())
401 log.error(traceback.format_exc())
402 Session.rollback()
402 Session.rollback()
403 raise
403 raise
404
404
405 @classmethod
405 @classmethod
406 def update(cls, users_group_id, form_data):
406 def update(cls, users_group_id, form_data):
407
407
408 try:
408 try:
409 users_group = cls.get(users_group_id, cache=False)
409 users_group = cls.get(users_group_id, cache=False)
410
410
411 for k, v in form_data.items():
411 for k, v in form_data.items():
412 if k == 'users_group_members':
412 if k == 'users_group_members':
413 users_group.members = []
413 users_group.members = []
414 Session.flush()
414 Session.flush()
415 members_list = []
415 members_list = []
416 if v:
416 if v:
417 v = [v] if isinstance(v, compat.string_types) else v
417 v = [v] if isinstance(v, compat.string_types) else v
418 for u_id in set(v):
418 for u_id in set(v):
419 member = UserGroupMember(users_group_id, u_id)
419 member = UserGroupMember(users_group_id, u_id)
420 members_list.append(member)
420 members_list.append(member)
421 setattr(users_group, 'members', members_list)
421 setattr(users_group, 'members', members_list)
422 setattr(users_group, k, v)
422 setattr(users_group, k, v)
423
423
424 Session.add(users_group)
424 Session.add(users_group)
425 Session.commit()
425 Session.commit()
426 except:
426 except:
427 log.error(traceback.format_exc())
427 log.error(traceback.format_exc())
428 Session.rollback()
428 Session.rollback()
429 raise
429 raise
430
430
431 @classmethod
431 @classmethod
432 def delete(cls, user_group_id):
432 def delete(cls, user_group_id):
433 try:
433 try:
434
434
435 # check if this group is not assigned to repo
435 # check if this group is not assigned to repo
436 assigned_groups = UserGroupRepoToPerm.query()\
436 assigned_groups = UserGroupRepoToPerm.query()\
437 .filter(UserGroupRepoToPerm.users_group_id ==
437 .filter(UserGroupRepoToPerm.users_group_id ==
438 user_group_id).all()
438 user_group_id).all()
439
439
440 if assigned_groups:
440 if assigned_groups:
441 raise UserGroupAssignedException(
441 raise UserGroupAssignedException(
442 'UserGroup assigned to %s' % assigned_groups)
442 'UserGroup assigned to %s' % assigned_groups)
443
443
444 users_group = cls.get(user_group_id, cache=False)
444 users_group = cls.get(user_group_id, cache=False)
445 Session.delete(users_group)
445 Session.delete(users_group)
446 Session.commit()
446 Session.commit()
447 except:
447 except:
448 log.error(traceback.format_exc())
448 log.error(traceback.format_exc())
449 Session.rollback()
449 Session.rollback()
450 raise
450 raise
451
451
452 class UserGroupMember(Base, BaseModel):
452 class UserGroupMember(Base, BaseModel):
453 __tablename__ = 'users_groups_members'
453 __tablename__ = 'users_groups_members'
454 __table_args__ = {'extend_existing':True}
454 __table_args__ = {'extend_existing':True}
455
455
456 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
456 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
457 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
457 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
458 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
458 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
459
459
460 user = relationship('User', lazy='joined')
460 user = relationship('User', lazy='joined')
461 users_group = relationship('UserGroup')
461 users_group = relationship('UserGroup')
462
462
463 def __init__(self, gr_id='', u_id=''):
463 def __init__(self, gr_id='', u_id=''):
464 self.users_group_id = gr_id
464 self.users_group_id = gr_id
465 self.user_id = u_id
465 self.user_id = u_id
466
466
467 @staticmethod
467 @staticmethod
468 def add_user_to_group(group, user):
468 def add_user_to_group(group, user):
469 ugm = UserGroupMember()
469 ugm = UserGroupMember()
470 ugm.users_group = group
470 ugm.users_group = group
471 ugm.user = user
471 ugm.user = user
472 Session.add(ugm)
472 Session.add(ugm)
473 Session.commit()
473 Session.commit()
474 return ugm
474 return ugm
475
475
476 class Repository(Base, BaseModel):
476 class Repository(Base, BaseModel):
477 __tablename__ = 'repositories'
477 __tablename__ = 'repositories'
478 __table_args__ = (UniqueConstraint('repo_name'), {'extend_existing':True},)
478 __table_args__ = (UniqueConstraint('repo_name'), {'extend_existing':True},)
479
479
480 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
480 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
481 repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None)
481 repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None)
482 clone_uri = Column("clone_uri", String(255), nullable=True, unique=False, default=None)
482 clone_uri = Column("clone_uri", String(255), nullable=True, unique=False, default=None)
483 repo_type = Column("repo_type", String(255), nullable=False, unique=False, default='hg')
483 repo_type = Column("repo_type", String(255), nullable=False, unique=False, default='hg')
484 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
484 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
485 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
485 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
486 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
486 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
487 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
487 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
488 description = Column("description", String(10000), nullable=True, unique=None, default=None)
488 description = Column("description", String(10000), nullable=True, unique=None, default=None)
489 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
489 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
490
490
491 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
491 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
492 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
492 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
493
493
494
494
495 user = relationship('User')
495 user = relationship('User')
496 fork = relationship('Repository', remote_side=repo_id)
496 fork = relationship('Repository', remote_side=repo_id)
497 group = relationship('RepoGroup')
497 group = relationship('RepoGroup')
498 repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
498 repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
499 users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
499 users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
500 stats = relationship('Statistics', cascade='all', uselist=False)
500 stats = relationship('Statistics', cascade='all', uselist=False)
501
501
502 followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all')
502 followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all')
503
503
504 logs = relationship('UserLog', cascade='all')
504 logs = relationship('UserLog', cascade='all')
505
505
506 def __repr__(self):
506 def __repr__(self):
507 return "<%s('%s:%s')>" % (self.__class__.__name__,
507 return "<%s('%s:%s')>" % (self.__class__.__name__,
508 self.repo_id, self.repo_name)
508 self.repo_id, self.repo_name)
509
509
510 @classmethod
510 @classmethod
511 def url_sep(cls):
511 def url_sep(cls):
512 return '/'
512 return '/'
513
513
514 @classmethod
514 @classmethod
515 def get_by_repo_name(cls, repo_name):
515 def get_by_repo_name(cls, repo_name):
516 q = Session.query(cls).filter(cls.repo_name == repo_name)
516 q = Session.query(cls).filter(cls.repo_name == repo_name)
517 q = q.options(joinedload(Repository.fork))\
517 q = q.options(joinedload(Repository.fork))\
518 .options(joinedload(Repository.user))\
518 .options(joinedload(Repository.user))\
519 .options(joinedload(Repository.group))
519 .options(joinedload(Repository.group))
520 return q.one()
520 return q.one()
521
521
522 @classmethod
522 @classmethod
523 def get_repo_forks(cls, repo_id):
523 def get_repo_forks(cls, repo_id):
524 return cls.query().filter(Repository.fork_id == repo_id)
524 return cls.query().filter(Repository.fork_id == repo_id)
525
525
526 @classmethod
526 @classmethod
527 def base_path(cls):
527 def base_path(cls):
528 """
528 """
529 Returns base path when all repos are stored
529 Returns base path when all repos are stored
530
530
531 :param cls:
531 :param cls:
532 """
532 """
533 q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key ==
533 q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key ==
534 cls.url_sep())
534 cls.url_sep())
535 q.options(FromCache("sql_cache_short", "repository_repo_path"))
535 q.options(FromCache("sql_cache_short", "repository_repo_path"))
536 return q.one().ui_value
536 return q.one().ui_value
537
537
538 @property
538 @property
539 def just_name(self):
539 def just_name(self):
540 return self.repo_name.split(Repository.url_sep())[-1]
540 return self.repo_name.split(Repository.url_sep())[-1]
541
541
542 @property
542 @property
543 def groups_with_parents(self):
543 def groups_with_parents(self):
544 groups = []
544 groups = []
545 if self.group is None:
545 if self.group is None:
546 return groups
546 return groups
547
547
548 cur_gr = self.group
548 cur_gr = self.group
549 groups.insert(0, cur_gr)
549 groups.insert(0, cur_gr)
550 while 1:
550 while 1:
551 gr = getattr(cur_gr, 'parent_group', None)
551 gr = getattr(cur_gr, 'parent_group', None)
552 cur_gr = cur_gr.parent_group
552 cur_gr = cur_gr.parent_group
553 if gr is None:
553 if gr is None:
554 break
554 break
555 groups.insert(0, gr)
555 groups.insert(0, gr)
556
556
557 return groups
557 return groups
558
558
559 @property
559 @property
560 def groups_and_repo(self):
560 def groups_and_repo(self):
561 return self.groups_with_parents, self.just_name
561 return self.groups_with_parents, self.just_name
562
562
563 @LazyProperty
563 @LazyProperty
564 def repo_path(self):
564 def repo_path(self):
565 """
565 """
566 Returns base full path for that repository means where it actually
566 Returns base full path for that repository means where it actually
567 exists on a filesystem
567 exists on a filesystem
568 """
568 """
569 q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key ==
569 q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key ==
570 Repository.url_sep())
570 Repository.url_sep())
571 q.options(FromCache("sql_cache_short", "repository_repo_path"))
571 q.options(FromCache("sql_cache_short", "repository_repo_path"))
572 return q.one().ui_value
572 return q.one().ui_value
573
573
574 @property
574 @property
575 def repo_full_path(self):
575 def repo_full_path(self):
576 p = [self.repo_path]
576 p = [self.repo_path]
577 # we need to split the name by / since this is how we store the
577 # we need to split the name by / since this is how we store the
578 # names in the database, but that eventually needs to be converted
578 # names in the database, but that eventually needs to be converted
579 # into a valid system path
579 # into a valid system path
580 p += self.repo_name.split(Repository.url_sep())
580 p += self.repo_name.split(Repository.url_sep())
581 return os.path.join(*p)
581 return os.path.join(*p)
582
582
583 def get_new_name(self, repo_name):
583 def get_new_name(self, repo_name):
584 """
584 """
585 returns new full repository name based on assigned group and new new
585 returns new full repository name based on assigned group and new new
586
586
587 :param group_name:
587 :param group_name:
588 """
588 """
589 path_prefix = self.group.full_path_splitted if self.group else []
589 path_prefix = self.group.full_path_splitted if self.group else []
590 return Repository.url_sep().join(path_prefix + [repo_name])
590 return Repository.url_sep().join(path_prefix + [repo_name])
591
591
592 @property
592 @property
593 def _config(self):
593 def _config(self):
594 """
594 """
595 Returns db based config object.
595 Returns db based config object.
596 """
596 """
597 from rhodecode.lib.utils import make_db_config
597 from rhodecode.lib.utils import make_db_config
598 return make_db_config(clear_session=False)
598 return make_db_config(clear_session=False)
599
599
600 @classmethod
600 @classmethod
601 def is_valid(cls, repo_name):
601 def is_valid(cls, repo_name):
602 """
602 """
603 returns True if given repo name is a valid filesystem repository
603 returns True if given repo name is a valid filesystem repository
604
604
605 :param cls:
605 :param cls:
606 :param repo_name:
606 :param repo_name:
607 """
607 """
608 from rhodecode.lib.utils import is_valid_repo
608 from rhodecode.lib.utils import is_valid_repo
609
609
610 return is_valid_repo(repo_name, cls.base_path())
610 return is_valid_repo(repo_name, cls.base_path())
611
611
612
612
613 #==========================================================================
613 #==========================================================================
614 # SCM PROPERTIES
614 # SCM PROPERTIES
615 #==========================================================================
615 #==========================================================================
616
616
617 def get_commit(self, rev):
617 def get_commit(self, rev):
618 return get_commit_safe(self.scm_instance, rev)
618 return get_commit_safe(self.scm_instance, rev)
619
619
620 @property
620 @property
621 def tip(self):
621 def tip(self):
622 return self.get_commit('tip')
622 return self.get_commit('tip')
623
623
624 @property
624 @property
625 def author(self):
625 def author(self):
626 return self.tip.author
626 return self.tip.author
627
627
628 @property
628 @property
629 def last_change(self):
629 def last_change(self):
630 return self.scm_instance.last_change
630 return self.scm_instance.last_change
631
631
632 #==========================================================================
632 #==========================================================================
633 # SCM CACHE INSTANCE
633 # SCM CACHE INSTANCE
634 #==========================================================================
634 #==========================================================================
635
635
636 @property
636 @property
637 def invalidate(self):
637 def invalidate(self):
638 return CacheInvalidation.invalidate(self.repo_name)
638 return CacheInvalidation.invalidate(self.repo_name)
639
639
640 def set_invalidate(self):
640 def set_invalidate(self):
641 """
641 """
642 set a cache for invalidation for this instance
642 set a cache for invalidation for this instance
643 """
643 """
644 CacheInvalidation.set_invalidate(self.repo_name)
644 CacheInvalidation.set_invalidate(self.repo_name)
645
645
646 @LazyProperty
646 @LazyProperty
647 def scm_instance(self):
647 def scm_instance(self):
648 return self.__get_instance()
648 return self.__get_instance()
649
649
650 @property
650 @property
651 def scm_instance_cached(self):
651 def scm_instance_cached(self):
652 return self.__get_instance()
652 return self.__get_instance()
653
653
654 def __get_instance(self):
654 def __get_instance(self):
655
655
656 repo_full_path = self.repo_full_path
656 repo_full_path = self.repo_full_path
657
657
658 try:
658 try:
659 alias = get_scm(repo_full_path)[0]
659 alias = get_scm(repo_full_path)[0]
660 log.debug('Creating instance of %s repository', alias)
660 log.debug('Creating instance of %s repository', alias)
661 backend = get_backend(alias)
661 backend = get_backend(alias)
662 except VCSError:
662 except VCSError:
663 log.error(traceback.format_exc())
663 log.error(traceback.format_exc())
664 log.error('Perhaps this repository is in db and not in '
664 log.error('Perhaps this repository is in db and not in '
665 'filesystem run rescan repositories with '
665 'filesystem run rescan repositories with '
666 '"destroy old data " option from admin panel')
666 '"destroy old data " option from admin panel')
667 return
667 return
668
668
669 if alias == 'hg':
669 if alias == 'hg':
670
670
671 repo = backend(safe_str(repo_full_path), create=False,
671 repo = backend(safe_str(repo_full_path), create=False,
672 config=self._config)
672 config=self._config)
673
673
674 else:
674 else:
675 repo = backend(repo_full_path, create=False)
675 repo = backend(repo_full_path, create=False)
676
676
677 return repo
677 return repo
678
678
679
679
680 class Group(Base, BaseModel):
680 class Group(Base, BaseModel):
681 __tablename__ = 'groups'
681 __tablename__ = 'groups'
682 __table_args__ = (UniqueConstraint('group_name', 'group_parent_id'),
682 __table_args__ = (UniqueConstraint('group_name', 'group_parent_id'),
683 CheckConstraint('group_id != group_parent_id'), {'extend_existing':True},)
683 {'extend_existing':True},)
684 __mapper_args__ = {'order_by':'group_name'}
684 __mapper_args__ = {'order_by':'group_name'}
685
685
686 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
686 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
687 group_name = Column("group_name", String(255), nullable=False, unique=True, default=None)
687 group_name = Column("group_name", String(255), nullable=False, unique=True, default=None)
688 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
688 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
689 group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None)
689 group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None)
690
690
691 parent_group = relationship('Group', remote_side=group_id)
691 parent_group = relationship('Group', remote_side=group_id)
692
692
693 def __init__(self, group_name='', parent_group=None):
693 def __init__(self, group_name='', parent_group=None):
694 self.group_name = group_name
694 self.group_name = group_name
695 self.parent_group = parent_group
695 self.parent_group = parent_group
696
696
697 def __repr__(self):
697 def __repr__(self):
698 return "<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
698 return "<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
699 self.group_name)
699 self.group_name)
700
700
701 @classmethod
701 @classmethod
702 def url_sep(cls):
702 def url_sep(cls):
703 return '/'
703 return '/'
704
704
705 @classmethod
705 @classmethod
706 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
706 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
707 if case_insensitive:
707 if case_insensitive:
708 gr = cls.query()\
708 gr = cls.query()\
709 .filter(cls.group_name.ilike(group_name))
709 .filter(cls.group_name.ilike(group_name))
710 else:
710 else:
711 gr = cls.query()\
711 gr = cls.query()\
712 .filter(cls.group_name == group_name)
712 .filter(cls.group_name == group_name)
713 if cache:
713 if cache:
714 gr = gr.options(FromCache("sql_cache_short",
714 gr = gr.options(FromCache("sql_cache_short",
715 "get_group_%s" % group_name))
715 "get_group_%s" % group_name))
716 return gr.scalar()
716 return gr.scalar()
717
717
718 @property
718 @property
719 def parents(self):
719 def parents(self):
720 parents_recursion_limit = 5
720 parents_recursion_limit = 5
721 groups = []
721 groups = []
722 if self.parent_group is None:
722 if self.parent_group is None:
723 return groups
723 return groups
724 cur_gr = self.parent_group
724 cur_gr = self.parent_group
725 groups.insert(0, cur_gr)
725 groups.insert(0, cur_gr)
726 cnt = 0
726 cnt = 0
727 while 1:
727 while 1:
728 cnt += 1
728 cnt += 1
729 gr = getattr(cur_gr, 'parent_group', None)
729 gr = getattr(cur_gr, 'parent_group', None)
730 cur_gr = cur_gr.parent_group
730 cur_gr = cur_gr.parent_group
731 if gr is None:
731 if gr is None:
732 break
732 break
733 if cnt == parents_recursion_limit:
733 if cnt == parents_recursion_limit:
734 # this will prevent accidental infinit loops
734 # this will prevent accidental infinit loops
735 log.error('group nested more than %s',
735 log.error('group nested more than %s',
736 parents_recursion_limit)
736 parents_recursion_limit)
737 break
737 break
738
738
739 groups.insert(0, gr)
739 groups.insert(0, gr)
740 return groups
740 return groups
741
741
742 @property
742 @property
743 def children(self):
743 def children(self):
744 return Group.query().filter(Group.parent_group == self)
744 return Group.query().filter(Group.parent_group == self)
745
745
746 @property
746 @property
747 def name(self):
747 def name(self):
748 return self.group_name.split(Group.url_sep())[-1]
748 return self.group_name.split(Group.url_sep())[-1]
749
749
750 @property
750 @property
751 def full_path(self):
751 def full_path(self):
752 return self.group_name
752 return self.group_name
753
753
754 @property
754 @property
755 def full_path_splitted(self):
755 def full_path_splitted(self):
756 return self.group_name.split(Group.url_sep())
756 return self.group_name.split(Group.url_sep())
757
757
758 @property
758 @property
759 def repositories(self):
759 def repositories(self):
760 return Repository.query().filter(Repository.group == self)
760 return Repository.query().filter(Repository.group == self)
761
761
762 @property
762 @property
763 def repositories_recursive_count(self):
763 def repositories_recursive_count(self):
764 cnt = self.repositories.count()
764 cnt = self.repositories.count()
765
765
766 def children_count(group):
766 def children_count(group):
767 cnt = 0
767 cnt = 0
768 for child in group.children:
768 for child in group.children:
769 cnt += child.repositories.count()
769 cnt += child.repositories.count()
770 cnt += children_count(child)
770 cnt += children_count(child)
771 return cnt
771 return cnt
772
772
773 return cnt + children_count(self)
773 return cnt + children_count(self)
774
774
775
775
776 def get_new_name(self, group_name):
776 def get_new_name(self, group_name):
777 """
777 """
778 returns new full group name based on parent and new name
778 returns new full group name based on parent and new name
779
779
780 :param group_name:
780 :param group_name:
781 """
781 """
782 path_prefix = (self.parent_group.full_path_splitted if
782 path_prefix = (self.parent_group.full_path_splitted if
783 self.parent_group else [])
783 self.parent_group else [])
784 return Group.url_sep().join(path_prefix + [group_name])
784 return Group.url_sep().join(path_prefix + [group_name])
785
785
786
786
787 class Permission(Base, BaseModel):
787 class Permission(Base, BaseModel):
788 __tablename__ = 'permissions'
788 __tablename__ = 'permissions'
789 __table_args__ = {'extend_existing':True}
789 __table_args__ = {'extend_existing':True}
790 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
790 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
791 permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None)
791 permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None)
792 permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None)
792 permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None)
793
793
794 def __repr__(self):
794 def __repr__(self):
795 return "<%s('%s:%s')>" % (self.__class__.__name__,
795 return "<%s('%s:%s')>" % (self.__class__.__name__,
796 self.permission_id, self.permission_name)
796 self.permission_id, self.permission_name)
797
797
798 @classmethod
798 @classmethod
799 def get_by_key(cls, key):
799 def get_by_key(cls, key):
800 return cls.query().filter(cls.permission_name == key).scalar()
800 return cls.query().filter(cls.permission_name == key).scalar()
801
801
802 class UserRepoToPerm(Base, BaseModel):
802 class UserRepoToPerm(Base, BaseModel):
803 __tablename__ = 'repo_to_perm'
803 __tablename__ = 'repo_to_perm'
804 __table_args__ = (UniqueConstraint('user_id', 'repository_id'), {'extend_existing':True})
804 __table_args__ = (UniqueConstraint('user_id', 'repository_id'), {'extend_existing':True})
805 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
805 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
806 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
806 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
807 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
807 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
808 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
808 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
809
809
810 user = relationship('User')
810 user = relationship('User')
811 permission = relationship('Permission')
811 permission = relationship('Permission')
812 repository = relationship('Repository')
812 repository = relationship('Repository')
813
813
814 class UserToPerm(Base, BaseModel):
814 class UserToPerm(Base, BaseModel):
815 __tablename__ = 'user_to_perm'
815 __tablename__ = 'user_to_perm'
816 __table_args__ = (UniqueConstraint('user_id', 'permission_id'), {'extend_existing':True})
816 __table_args__ = (UniqueConstraint('user_id', 'permission_id'), {'extend_existing':True})
817 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
817 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
818 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
818 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
819 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
819 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
820
820
821 user = relationship('User')
821 user = relationship('User')
822 permission = relationship('Permission')
822 permission = relationship('Permission')
823
823
824 @classmethod
824 @classmethod
825 def has_perm(cls, user_id, perm):
825 def has_perm(cls, user_id, perm):
826 if not isinstance(perm, Permission):
826 if not isinstance(perm, Permission):
827 raise Exception('perm needs to be an instance of Permission class')
827 raise Exception('perm needs to be an instance of Permission class')
828
828
829 return cls.query().filter(cls.user_id == user_id)\
829 return cls.query().filter(cls.user_id == user_id)\
830 .filter(cls.permission == perm).scalar() is not None
830 .filter(cls.permission == perm).scalar() is not None
831
831
832 @classmethod
832 @classmethod
833 def grant_perm(cls, user_id, perm):
833 def grant_perm(cls, user_id, perm):
834 if not isinstance(perm, Permission):
834 if not isinstance(perm, Permission):
835 raise Exception('perm needs to be an instance of Permission class')
835 raise Exception('perm needs to be an instance of Permission class')
836
836
837 new = cls()
837 new = cls()
838 new.user_id = user_id
838 new.user_id = user_id
839 new.permission = perm
839 new.permission = perm
840 try:
840 try:
841 Session.add(new)
841 Session.add(new)
842 Session.commit()
842 Session.commit()
843 except:
843 except:
844 Session.rollback()
844 Session.rollback()
845
845
846
846
847 @classmethod
847 @classmethod
848 def revoke_perm(cls, user_id, perm):
848 def revoke_perm(cls, user_id, perm):
849 if not isinstance(perm, Permission):
849 if not isinstance(perm, Permission):
850 raise Exception('perm needs to be an instance of Permission class')
850 raise Exception('perm needs to be an instance of Permission class')
851
851
852 try:
852 try:
853 cls.query().filter(cls.user_id == user_id) \
853 cls.query().filter(cls.user_id == user_id) \
854 .filter(cls.permission == perm).delete()
854 .filter(cls.permission == perm).delete()
855 Session.commit()
855 Session.commit()
856 except:
856 except:
857 Session.rollback()
857 Session.rollback()
858
858
859 class UserGroupRepoToPerm(Base, BaseModel):
859 class UserGroupRepoToPerm(Base, BaseModel):
860 __tablename__ = 'users_group_repo_to_perm'
860 __tablename__ = 'users_group_repo_to_perm'
861 __table_args__ = (UniqueConstraint('repository_id', 'users_group_id', 'permission_id'), {'extend_existing':True})
861 __table_args__ = (UniqueConstraint('repository_id', 'users_group_id', 'permission_id'), {'extend_existing':True})
862 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
862 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
863 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
863 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
864 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
864 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
865 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
865 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
866
866
867 users_group = relationship('UserGroup')
867 users_group = relationship('UserGroup')
868 permission = relationship('Permission')
868 permission = relationship('Permission')
869 repository = relationship('Repository')
869 repository = relationship('Repository')
870
870
871 def __repr__(self):
871 def __repr__(self):
872 return '<userGroup:%s => %s >' % (self.users_group, self.repository)
872 return '<userGroup:%s => %s >' % (self.users_group, self.repository)
873
873
874 class UserGroupToPerm(Base, BaseModel):
874 class UserGroupToPerm(Base, BaseModel):
875 __tablename__ = 'users_group_to_perm'
875 __tablename__ = 'users_group_to_perm'
876 __table_args__ = {'extend_existing':True}
876 __table_args__ = {'extend_existing':True}
877 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
877 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
878 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
878 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
879 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
879 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
880
880
881 users_group = relationship('UserGroup')
881 users_group = relationship('UserGroup')
882 permission = relationship('Permission')
882 permission = relationship('Permission')
883
883
884
884
885 @classmethod
885 @classmethod
886 def has_perm(cls, users_group_id, perm):
886 def has_perm(cls, users_group_id, perm):
887 if not isinstance(perm, Permission):
887 if not isinstance(perm, Permission):
888 raise Exception('perm needs to be an instance of Permission class')
888 raise Exception('perm needs to be an instance of Permission class')
889
889
890 return cls.query().filter(cls.users_group_id ==
890 return cls.query().filter(cls.users_group_id ==
891 users_group_id)\
891 users_group_id)\
892 .filter(cls.permission == perm)\
892 .filter(cls.permission == perm)\
893 .scalar() is not None
893 .scalar() is not None
894
894
895 @classmethod
895 @classmethod
896 def grant_perm(cls, users_group_id, perm):
896 def grant_perm(cls, users_group_id, perm):
897 if not isinstance(perm, Permission):
897 if not isinstance(perm, Permission):
898 raise Exception('perm needs to be an instance of Permission class')
898 raise Exception('perm needs to be an instance of Permission class')
899
899
900 new = cls()
900 new = cls()
901 new.users_group_id = users_group_id
901 new.users_group_id = users_group_id
902 new.permission = perm
902 new.permission = perm
903 try:
903 try:
904 Session.add(new)
904 Session.add(new)
905 Session.commit()
905 Session.commit()
906 except:
906 except:
907 Session.rollback()
907 Session.rollback()
908
908
909
909
910 @classmethod
910 @classmethod
911 def revoke_perm(cls, users_group_id, perm):
911 def revoke_perm(cls, users_group_id, perm):
912 if not isinstance(perm, Permission):
912 if not isinstance(perm, Permission):
913 raise Exception('perm needs to be an instance of Permission class')
913 raise Exception('perm needs to be an instance of Permission class')
914
914
915 try:
915 try:
916 cls.query().filter(cls.users_group_id == users_group_id) \
916 cls.query().filter(cls.users_group_id == users_group_id) \
917 .filter(cls.permission == perm).delete()
917 .filter(cls.permission == perm).delete()
918 Session.commit()
918 Session.commit()
919 except:
919 except:
920 Session.rollback()
920 Session.rollback()
921
921
922
922
923 class UserRepoGroupToPerm(Base, BaseModel):
923 class UserRepoGroupToPerm(Base, BaseModel):
924 __tablename__ = 'group_to_perm'
924 __tablename__ = 'group_to_perm'
925 __table_args__ = (UniqueConstraint('group_id', 'permission_id'), {'extend_existing':True})
925 __table_args__ = (UniqueConstraint('group_id', 'permission_id'), {'extend_existing':True})
926
926
927 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
927 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
928 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
928 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
929 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
929 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
930 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
930 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
931
931
932 user = relationship('User')
932 user = relationship('User')
933 permission = relationship('Permission')
933 permission = relationship('Permission')
934 group = relationship('RepoGroup')
934 group = relationship('RepoGroup')
935
935
936 class Statistics(Base, BaseModel):
936 class Statistics(Base, BaseModel):
937 __tablename__ = 'statistics'
937 __tablename__ = 'statistics'
938 __table_args__ = (UniqueConstraint('repository_id'), {'extend_existing':True})
938 __table_args__ = (UniqueConstraint('repository_id'), {'extend_existing':True})
939 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
939 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
940 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
940 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
941 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
941 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
942 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
942 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
943 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
943 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
944 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
944 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
945
945
946 repository = relationship('Repository', single_parent=True)
946 repository = relationship('Repository', single_parent=True)
947
947
948 class UserFollowing(Base, BaseModel):
948 class UserFollowing(Base, BaseModel):
949 __tablename__ = 'user_followings'
949 __tablename__ = 'user_followings'
950 __table_args__ = (UniqueConstraint('user_id', 'follows_repository_id'),
950 __table_args__ = (UniqueConstraint('user_id', 'follows_repository_id'),
951 UniqueConstraint('user_id', 'follows_user_id')
951 UniqueConstraint('user_id', 'follows_user_id')
952 , {'extend_existing':True})
952 , {'extend_existing':True})
953
953
954 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
954 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
955 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
955 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
956 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
956 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
957 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
957 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
958 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
958 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
959
959
960 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
960 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
961
961
962 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
962 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
963 follows_repository = relationship('Repository', order_by='Repository.repo_name')
963 follows_repository = relationship('Repository', order_by='Repository.repo_name')
964
964
965
965
966 @classmethod
966 @classmethod
967 def get_repo_followers(cls, repo_id):
967 def get_repo_followers(cls, repo_id):
968 return cls.query().filter(cls.follows_repo_id == repo_id)
968 return cls.query().filter(cls.follows_repo_id == repo_id)
969
969
970 class CacheInvalidation(Base, BaseModel):
970 class CacheInvalidation(Base, BaseModel):
971 __tablename__ = 'cache_invalidation'
971 __tablename__ = 'cache_invalidation'
972 __table_args__ = (UniqueConstraint('cache_key'), {'extend_existing':True})
972 __table_args__ = (UniqueConstraint('cache_key'), {'extend_existing':True})
973 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
973 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
974 cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None)
974 cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None)
975 cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None)
975 cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None)
976 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
976 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
977
977
978
978
979 def __init__(self, cache_key, cache_args=''):
979 def __init__(self, cache_key, cache_args=''):
980 self.cache_key = cache_key
980 self.cache_key = cache_key
981 self.cache_args = cache_args
981 self.cache_args = cache_args
982 self.cache_active = False
982 self.cache_active = False
983
983
984 def __repr__(self):
984 def __repr__(self):
985 return "<%s('%s:%s')>" % (self.__class__.__name__,
985 return "<%s('%s:%s')>" % (self.__class__.__name__,
986 self.cache_id, self.cache_key)
986 self.cache_id, self.cache_key)
987
987
988 @classmethod
988 @classmethod
989 def invalidate(cls, key):
989 def invalidate(cls, key):
990 """
990 """
991 Returns Invalidation object if this given key should be invalidated
991 Returns Invalidation object if this given key should be invalidated
992 None otherwise. `cache_active = False` means that this cache
992 None otherwise. `cache_active = False` means that this cache
993 state is not valid and needs to be invalidated
993 state is not valid and needs to be invalidated
994
994
995 :param key:
995 :param key:
996 """
996 """
997 return cls.query()\
997 return cls.query()\
998 .filter(CacheInvalidation.cache_key == key)\
998 .filter(CacheInvalidation.cache_key == key)\
999 .filter(CacheInvalidation.cache_active == False)\
999 .filter(CacheInvalidation.cache_active == False)\
1000 .scalar()
1000 .scalar()
1001
1001
1002 @classmethod
1002 @classmethod
1003 def set_invalidate(cls, key):
1003 def set_invalidate(cls, key):
1004 """
1004 """
1005 Mark this Cache key for invalidation
1005 Mark this Cache key for invalidation
1006
1006
1007 :param key:
1007 :param key:
1008 """
1008 """
1009
1009
1010 log.debug('marking %s for invalidation', key)
1010 log.debug('marking %s for invalidation', key)
1011 inv_obj = Session.query(cls)\
1011 inv_obj = Session.query(cls)\
1012 .filter(cls.cache_key == key).scalar()
1012 .filter(cls.cache_key == key).scalar()
1013 if inv_obj:
1013 if inv_obj:
1014 inv_obj.cache_active = False
1014 inv_obj.cache_active = False
1015 else:
1015 else:
1016 log.debug('cache key not found in invalidation db -> creating one')
1016 log.debug('cache key not found in invalidation db -> creating one')
1017 inv_obj = CacheInvalidation(key)
1017 inv_obj = CacheInvalidation(key)
1018
1018
1019 try:
1019 try:
1020 Session.add(inv_obj)
1020 Session.add(inv_obj)
1021 Session.commit()
1021 Session.commit()
1022 except Exception:
1022 except Exception:
1023 log.error(traceback.format_exc())
1023 log.error(traceback.format_exc())
1024 Session.rollback()
1024 Session.rollback()
1025
1025
1026 @classmethod
1026 @classmethod
1027 def set_valid(cls, key):
1027 def set_valid(cls, key):
1028 """
1028 """
1029 Mark this cache key as active and currently cached
1029 Mark this cache key as active and currently cached
1030
1030
1031 :param key:
1031 :param key:
1032 """
1032 """
1033 inv_obj = Session.query(CacheInvalidation)\
1033 inv_obj = Session.query(CacheInvalidation)\
1034 .filter(CacheInvalidation.cache_key == key).scalar()
1034 .filter(CacheInvalidation.cache_key == key).scalar()
1035 inv_obj.cache_active = True
1035 inv_obj.cache_active = True
1036 Session.add(inv_obj)
1036 Session.add(inv_obj)
1037 Session.commit()
1037 Session.commit()
1038
1038
1039 class DbMigrateVersion(Base, BaseModel):
1039 class DbMigrateVersion(Base, BaseModel):
1040 __tablename__ = 'db_migrate_version'
1040 __tablename__ = 'db_migrate_version'
1041 __table_args__ = {'extend_existing':True}
1041 __table_args__ = {'extend_existing':True}
1042 repository_id = Column('repository_id', String(250), primary_key=True)
1042 repository_id = Column('repository_id', String(250), primary_key=True)
1043 repository_path = Column('repository_path', Text)
1043 repository_path = Column('repository_path', Text)
1044 version = Column('version', Integer)
1044 version = Column('version', Integer)
@@ -1,1264 +1,1263 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2019 RhodeCode GmbH
3 # Copyright (C) 2010-2019 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import os
21 import os
22 import logging
22 import logging
23 import datetime
23 import datetime
24 import traceback
24 import traceback
25 from collections import defaultdict
25 from collections import defaultdict
26
26
27 from sqlalchemy import *
27 from sqlalchemy import *
28 from sqlalchemy.ext.hybrid import hybrid_property
28 from sqlalchemy.ext.hybrid import hybrid_property
29 from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
29 from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
30 from beaker.cache import cache_region, region_invalidate
30 from beaker.cache import cache_region, region_invalidate
31
31
32 from rhodecode.lib.vcs import get_backend
32 from rhodecode.lib.vcs import get_backend
33 from rhodecode.lib.vcs.utils.helpers import get_scm
33 from rhodecode.lib.vcs.utils.helpers import get_scm
34 from rhodecode.lib.vcs.exceptions import VCSError
34 from rhodecode.lib.vcs.exceptions import VCSError
35 from zope.cachedescriptors.property import Lazy as LazyProperty
35 from zope.cachedescriptors.property import Lazy as LazyProperty
36
36
37 from rhodecode.lib.utils2 import str2bool, safe_str, get_commit_safe, \
37 from rhodecode.lib.utils2 import str2bool, safe_str, get_commit_safe, \
38 safe_unicode
38 safe_unicode
39 from rhodecode.lib.ext_json import json
39 from rhodecode.lib.ext_json import json
40 from rhodecode.lib.caching_query import FromCache
40 from rhodecode.lib.caching_query import FromCache
41
41
42 from rhodecode.model.meta import Base, Session
42 from rhodecode.model.meta import Base, Session
43 import hashlib
43 import hashlib
44
44
45
45
46 log = logging.getLogger(__name__)
46 log = logging.getLogger(__name__)
47
47
48 #==============================================================================
48 #==============================================================================
49 # BASE CLASSES
49 # BASE CLASSES
50 #==============================================================================
50 #==============================================================================
51
51
52 _hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest()
52 _hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest()
53
53
54
54
55 class ModelSerializer(json.JSONEncoder):
55 class ModelSerializer(json.JSONEncoder):
56 """
56 """
57 Simple Serializer for JSON,
57 Simple Serializer for JSON,
58
58
59 usage::
59 usage::
60
60
61 to make object customized for serialization implement a __json__
61 to make object customized for serialization implement a __json__
62 method that will return a dict for serialization into json
62 method that will return a dict for serialization into json
63
63
64 example::
64 example::
65
65
66 class Task(object):
66 class Task(object):
67
67
68 def __init__(self, name, value):
68 def __init__(self, name, value):
69 self.name = name
69 self.name = name
70 self.value = value
70 self.value = value
71
71
72 def __json__(self):
72 def __json__(self):
73 return dict(name=self.name,
73 return dict(name=self.name,
74 value=self.value)
74 value=self.value)
75
75
76 """
76 """
77
77
78 def default(self, obj):
78 def default(self, obj):
79
79
80 if hasattr(obj, '__json__'):
80 if hasattr(obj, '__json__'):
81 return obj.__json__()
81 return obj.__json__()
82 else:
82 else:
83 return json.JSONEncoder.default(self, obj)
83 return json.JSONEncoder.default(self, obj)
84
84
85
85
86 class BaseModel(object):
86 class BaseModel(object):
87 """
87 """
88 Base Model for all classess
88 Base Model for all classess
89 """
89 """
90
90
91 @classmethod
91 @classmethod
92 def _get_keys(cls):
92 def _get_keys(cls):
93 """return column names for this model """
93 """return column names for this model """
94 return class_mapper(cls).c.keys()
94 return class_mapper(cls).c.keys()
95
95
96 def get_dict(self):
96 def get_dict(self):
97 """
97 """
98 return dict with keys and values corresponding
98 return dict with keys and values corresponding
99 to this model data """
99 to this model data """
100
100
101 d = {}
101 d = {}
102 for k in self._get_keys():
102 for k in self._get_keys():
103 d[k] = getattr(self, k)
103 d[k] = getattr(self, k)
104
104
105 # also use __json__() if present to get additional fields
105 # also use __json__() if present to get additional fields
106 for k, val in getattr(self, '__json__', lambda: {})().iteritems():
106 for k, val in getattr(self, '__json__', lambda: {})().iteritems():
107 d[k] = val
107 d[k] = val
108 return d
108 return d
109
109
110 def get_appstruct(self):
110 def get_appstruct(self):
111 """return list with keys and values tupples corresponding
111 """return list with keys and values tupples corresponding
112 to this model data """
112 to this model data """
113
113
114 l = []
114 l = []
115 for k in self._get_keys():
115 for k in self._get_keys():
116 l.append((k, getattr(self, k),))
116 l.append((k, getattr(self, k),))
117 return l
117 return l
118
118
119 def populate_obj(self, populate_dict):
119 def populate_obj(self, populate_dict):
120 """populate model with data from given populate_dict"""
120 """populate model with data from given populate_dict"""
121
121
122 for k in self._get_keys():
122 for k in self._get_keys():
123 if k in populate_dict:
123 if k in populate_dict:
124 setattr(self, k, populate_dict[k])
124 setattr(self, k, populate_dict[k])
125
125
126 @classmethod
126 @classmethod
127 def query(cls):
127 def query(cls):
128 return Session.query(cls)
128 return Session.query(cls)
129
129
130 @classmethod
130 @classmethod
131 def get(cls, id_):
131 def get(cls, id_):
132 if id_:
132 if id_:
133 return cls.query().get(id_)
133 return cls.query().get(id_)
134
134
135 @classmethod
135 @classmethod
136 def getAll(cls):
136 def getAll(cls):
137 return cls.query().all()
137 return cls.query().all()
138
138
139 @classmethod
139 @classmethod
140 def delete(cls, id_):
140 def delete(cls, id_):
141 obj = cls.query().get(id_)
141 obj = cls.query().get(id_)
142 Session.delete(obj)
142 Session.delete(obj)
143
143
144 def __repr__(self):
144 def __repr__(self):
145 if hasattr(self, '__unicode__'):
145 if hasattr(self, '__unicode__'):
146 # python repr needs to return str
146 # python repr needs to return str
147 return safe_str(self.__unicode__())
147 return safe_str(self.__unicode__())
148 return '<DB:%s>' % (self.__class__.__name__)
148 return '<DB:%s>' % (self.__class__.__name__)
149
149
150
150
151 class RhodeCodeSetting(Base, BaseModel):
151 class RhodeCodeSetting(Base, BaseModel):
152 __tablename__ = 'rhodecode_settings'
152 __tablename__ = 'rhodecode_settings'
153 __table_args__ = (
153 __table_args__ = (
154 UniqueConstraint('app_settings_name'),
154 UniqueConstraint('app_settings_name'),
155 {'extend_existing': True, 'mysql_engine':'InnoDB',
155 {'extend_existing': True, 'mysql_engine':'InnoDB',
156 'mysql_charset': 'utf8'}
156 'mysql_charset': 'utf8'}
157 )
157 )
158 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
158 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
159 app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None)
159 app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None)
160 _app_settings_value = Column("app_settings_value", String(255), nullable=True, unique=None, default=None)
160 _app_settings_value = Column("app_settings_value", String(255), nullable=True, unique=None, default=None)
161
161
162 def __init__(self, k='', v=''):
162 def __init__(self, k='', v=''):
163 self.app_settings_name = k
163 self.app_settings_name = k
164 self.app_settings_value = v
164 self.app_settings_value = v
165
165
166 @validates('_app_settings_value')
166 @validates('_app_settings_value')
167 def validate_settings_value(self, key, val):
167 def validate_settings_value(self, key, val):
168 assert type(val) == unicode
168 assert type(val) == unicode
169 return val
169 return val
170
170
171 @hybrid_property
171 @hybrid_property
172 def app_settings_value(self):
172 def app_settings_value(self):
173 v = self._app_settings_value
173 v = self._app_settings_value
174 if self.app_settings_name == 'ldap_active':
174 if self.app_settings_name == 'ldap_active':
175 v = str2bool(v)
175 v = str2bool(v)
176 return v
176 return v
177
177
178 @app_settings_value.setter
178 @app_settings_value.setter
179 def app_settings_value(self, val):
179 def app_settings_value(self, val):
180 """
180 """
181 Setter that will always make sure we use unicode in app_settings_value
181 Setter that will always make sure we use unicode in app_settings_value
182
182
183 :param val:
183 :param val:
184 """
184 """
185 self._app_settings_value = safe_unicode(val)
185 self._app_settings_value = safe_unicode(val)
186
186
187 def __unicode__(self):
187 def __unicode__(self):
188 return u"<%s('%s:%s')>" % (
188 return u"<%s('%s:%s')>" % (
189 self.__class__.__name__,
189 self.__class__.__name__,
190 self.app_settings_name, self.app_settings_value
190 self.app_settings_name, self.app_settings_value
191 )
191 )
192
192
193 @classmethod
193 @classmethod
194 def get_by_name(cls, ldap_key):
194 def get_by_name(cls, ldap_key):
195 return cls.query()\
195 return cls.query()\
196 .filter(cls.app_settings_name == ldap_key).scalar()
196 .filter(cls.app_settings_name == ldap_key).scalar()
197
197
198 @classmethod
198 @classmethod
199 def get_app_settings(cls, cache=False):
199 def get_app_settings(cls, cache=False):
200
200
201 ret = cls.query()
201 ret = cls.query()
202
202
203 if cache:
203 if cache:
204 ret = ret.options(FromCache("sql_cache_short", "get_hg_settings"))
204 ret = ret.options(FromCache("sql_cache_short", "get_hg_settings"))
205
205
206 if not ret:
206 if not ret:
207 raise Exception('Could not get application settings !')
207 raise Exception('Could not get application settings !')
208 settings = {}
208 settings = {}
209 for each in ret:
209 for each in ret:
210 settings['rhodecode_' + each.app_settings_name] = \
210 settings['rhodecode_' + each.app_settings_name] = \
211 each.app_settings_value
211 each.app_settings_value
212
212
213 return settings
213 return settings
214
214
215 @classmethod
215 @classmethod
216 def get_ldap_settings(cls, cache=False):
216 def get_ldap_settings(cls, cache=False):
217 ret = cls.query()\
217 ret = cls.query()\
218 .filter(cls.app_settings_name.startswith('ldap_')).all()
218 .filter(cls.app_settings_name.startswith('ldap_')).all()
219 fd = {}
219 fd = {}
220 for row in ret:
220 for row in ret:
221 fd.update({row.app_settings_name:row.app_settings_value})
221 fd.update({row.app_settings_name:row.app_settings_value})
222
222
223 return fd
223 return fd
224
224
225
225
226 class RhodeCodeUi(Base, BaseModel):
226 class RhodeCodeUi(Base, BaseModel):
227 __tablename__ = 'rhodecode_ui'
227 __tablename__ = 'rhodecode_ui'
228 __table_args__ = (
228 __table_args__ = (
229 UniqueConstraint('ui_key'),
229 UniqueConstraint('ui_key'),
230 {'extend_existing': True, 'mysql_engine':'InnoDB',
230 {'extend_existing': True, 'mysql_engine':'InnoDB',
231 'mysql_charset': 'utf8'}
231 'mysql_charset': 'utf8'}
232 )
232 )
233
233
234 HOOK_REPO_SIZE = 'changegroup.repo_size'
234 HOOK_REPO_SIZE = 'changegroup.repo_size'
235 HOOK_PUSH = 'pretxnchangegroup.push_logger'
235 HOOK_PUSH = 'pretxnchangegroup.push_logger'
236 HOOK_PULL = 'preoutgoing.pull_logger'
236 HOOK_PULL = 'preoutgoing.pull_logger'
237
237
238 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
238 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
239 ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None)
239 ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None)
240 ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None)
240 ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None)
241 ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None)
241 ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None)
242 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
242 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
243
243
244 @classmethod
244 @classmethod
245 def get_by_key(cls, key):
245 def get_by_key(cls, key):
246 return cls.query().filter(cls.ui_key == key)
246 return cls.query().filter(cls.ui_key == key)
247
247
248 @classmethod
248 @classmethod
249 def get_builtin_hooks(cls):
249 def get_builtin_hooks(cls):
250 q = cls.query()
250 q = cls.query()
251 q = q.filter(cls.ui_key.in_([cls.HOOK_REPO_SIZE,
251 q = q.filter(cls.ui_key.in_([cls.HOOK_REPO_SIZE,
252 cls.HOOK_PUSH, cls.HOOK_PULL]))
252 cls.HOOK_PUSH, cls.HOOK_PULL]))
253 return q.all()
253 return q.all()
254
254
255 @classmethod
255 @classmethod
256 def get_custom_hooks(cls):
256 def get_custom_hooks(cls):
257 q = cls.query()
257 q = cls.query()
258 q = q.filter(~cls.ui_key.in_([cls.HOOK_REPO_SIZE,
258 q = q.filter(~cls.ui_key.in_([cls.HOOK_REPO_SIZE,
259 cls.HOOK_PUSH, cls.HOOK_PULL]))
259 cls.HOOK_PUSH, cls.HOOK_PULL]))
260 q = q.filter(cls.ui_section == 'hooks')
260 q = q.filter(cls.ui_section == 'hooks')
261 return q.all()
261 return q.all()
262
262
263 @classmethod
263 @classmethod
264 def create_or_update_hook(cls, key, val):
264 def create_or_update_hook(cls, key, val):
265 new_ui = cls.get_by_key(key).scalar() or cls()
265 new_ui = cls.get_by_key(key).scalar() or cls()
266 new_ui.ui_section = 'hooks'
266 new_ui.ui_section = 'hooks'
267 new_ui.ui_active = True
267 new_ui.ui_active = True
268 new_ui.ui_key = key
268 new_ui.ui_key = key
269 new_ui.ui_value = val
269 new_ui.ui_value = val
270
270
271 Session.add(new_ui)
271 Session.add(new_ui)
272
272
273
273
274 class User(Base, BaseModel):
274 class User(Base, BaseModel):
275 __tablename__ = 'users'
275 __tablename__ = 'users'
276 __table_args__ = (
276 __table_args__ = (
277 UniqueConstraint('username'), UniqueConstraint('email'),
277 UniqueConstraint('username'), UniqueConstraint('email'),
278 {'extend_existing': True, 'mysql_engine':'InnoDB',
278 {'extend_existing': True, 'mysql_engine':'InnoDB',
279 'mysql_charset': 'utf8'}
279 'mysql_charset': 'utf8'}
280 )
280 )
281 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
281 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
282 username = Column("username", String(255), nullable=True, unique=None, default=None)
282 username = Column("username", String(255), nullable=True, unique=None, default=None)
283 password = Column("password", String(255), nullable=True, unique=None, default=None)
283 password = Column("password", String(255), nullable=True, unique=None, default=None)
284 active = Column("active", Boolean(), nullable=True, unique=None, default=None)
284 active = Column("active", Boolean(), nullable=True, unique=None, default=None)
285 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
285 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
286 name = Column("name", String(255), nullable=True, unique=None, default=None)
286 name = Column("name", String(255), nullable=True, unique=None, default=None)
287 lastname = Column("lastname", String(255), nullable=True, unique=None, default=None)
287 lastname = Column("lastname", String(255), nullable=True, unique=None, default=None)
288 _email = Column("email", String(255), nullable=True, unique=None, default=None)
288 _email = Column("email", String(255), nullable=True, unique=None, default=None)
289 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
289 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
290 ldap_dn = Column("ldap_dn", String(255), nullable=True, unique=None, default=None)
290 ldap_dn = Column("ldap_dn", String(255), nullable=True, unique=None, default=None)
291 api_key = Column("api_key", String(255), nullable=True, unique=None, default=None)
291 api_key = Column("api_key", String(255), nullable=True, unique=None, default=None)
292
292
293 user_log = relationship('UserLog', cascade='all')
293 user_log = relationship('UserLog', cascade='all')
294 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
294 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
295
295
296 repositories = relationship('Repository')
296 repositories = relationship('Repository')
297 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
297 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
298 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
298 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
299 repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all')
299 repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all')
300
300
301 group_member = relationship('UserGroupMember', cascade='all')
301 group_member = relationship('UserGroupMember', cascade='all')
302
302
303 notifications = relationship('UserNotification', cascade='all')
303 notifications = relationship('UserNotification', cascade='all')
304 # notifications assigned to this user
304 # notifications assigned to this user
305 user_created_notifications = relationship('Notification', cascade='all')
305 user_created_notifications = relationship('Notification', cascade='all')
306 # comments created by this user
306 # comments created by this user
307 user_comments = relationship('ChangesetComment', cascade='all')
307 user_comments = relationship('ChangesetComment', cascade='all')
308
308
309 @hybrid_property
309 @hybrid_property
310 def email(self):
310 def email(self):
311 return self._email
311 return self._email
312
312
313 @email.setter
313 @email.setter
314 def email(self, val):
314 def email(self, val):
315 self._email = val.lower() if val else None
315 self._email = val.lower() if val else None
316
316
317 @property
317 @property
318 def full_name(self):
318 def full_name(self):
319 return '%s %s' % (self.name, self.lastname)
319 return '%s %s' % (self.name, self.lastname)
320
320
321 @property
321 @property
322 def full_name_or_username(self):
322 def full_name_or_username(self):
323 return ('%s %s' % (self.name, self.lastname)
323 return ('%s %s' % (self.name, self.lastname)
324 if (self.name and self.lastname) else self.username)
324 if (self.name and self.lastname) else self.username)
325
325
326 @property
326 @property
327 def full_contact(self):
327 def full_contact(self):
328 return '%s %s <%s>' % (self.name, self.lastname, self.email)
328 return '%s %s <%s>' % (self.name, self.lastname, self.email)
329
329
330 @property
330 @property
331 def short_contact(self):
331 def short_contact(self):
332 return '%s %s' % (self.name, self.lastname)
332 return '%s %s' % (self.name, self.lastname)
333
333
334 @property
334 @property
335 def is_admin(self):
335 def is_admin(self):
336 return self.admin
336 return self.admin
337
337
338 def __unicode__(self):
338 def __unicode__(self):
339 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
339 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
340 self.user_id, self.username)
340 self.user_id, self.username)
341
341
342 @classmethod
342 @classmethod
343 def get_by_username(cls, username, case_insensitive=False, cache=False):
343 def get_by_username(cls, username, case_insensitive=False, cache=False):
344 if case_insensitive:
344 if case_insensitive:
345 q = cls.query().filter(cls.username.ilike(username))
345 q = cls.query().filter(cls.username.ilike(username))
346 else:
346 else:
347 q = cls.query().filter(cls.username == username)
347 q = cls.query().filter(cls.username == username)
348
348
349 if cache:
349 if cache:
350 q = q.options(FromCache(
350 q = q.options(FromCache(
351 "sql_cache_short",
351 "sql_cache_short",
352 "get_user_%s" % _hash_key(username)
352 "get_user_%s" % _hash_key(username)
353 )
353 )
354 )
354 )
355 return q.scalar()
355 return q.scalar()
356
356
357 @classmethod
357 @classmethod
358 def get_by_auth_token(cls, auth_token, cache=False):
358 def get_by_auth_token(cls, auth_token, cache=False):
359 q = cls.query().filter(cls.api_key == auth_token)
359 q = cls.query().filter(cls.api_key == auth_token)
360
360
361 if cache:
361 if cache:
362 q = q.options(FromCache("sql_cache_short",
362 q = q.options(FromCache("sql_cache_short",
363 "get_auth_token_%s" % auth_token))
363 "get_auth_token_%s" % auth_token))
364 return q.scalar()
364 return q.scalar()
365
365
366 @classmethod
366 @classmethod
367 def get_by_email(cls, email, case_insensitive=False, cache=False):
367 def get_by_email(cls, email, case_insensitive=False, cache=False):
368 if case_insensitive:
368 if case_insensitive:
369 q = cls.query().filter(cls.email.ilike(email))
369 q = cls.query().filter(cls.email.ilike(email))
370 else:
370 else:
371 q = cls.query().filter(cls.email == email)
371 q = cls.query().filter(cls.email == email)
372
372
373 if cache:
373 if cache:
374 q = q.options(FromCache("sql_cache_short",
374 q = q.options(FromCache("sql_cache_short",
375 "get_auth_token_%s" % email))
375 "get_auth_token_%s" % email))
376 return q.scalar()
376 return q.scalar()
377
377
378 def update_lastlogin(self):
378 def update_lastlogin(self):
379 """Update user lastlogin"""
379 """Update user lastlogin"""
380 self.last_login = datetime.datetime.now()
380 self.last_login = datetime.datetime.now()
381 Session.add(self)
381 Session.add(self)
382 log.debug('updated user %s lastlogin', self.username)
382 log.debug('updated user %s lastlogin', self.username)
383
383
384 def __json__(self):
384 def __json__(self):
385 return dict(
385 return dict(
386 user_id=self.user_id,
386 user_id=self.user_id,
387 first_name=self.name,
387 first_name=self.name,
388 last_name=self.lastname,
388 last_name=self.lastname,
389 email=self.email,
389 email=self.email,
390 full_name=self.full_name,
390 full_name=self.full_name,
391 full_name_or_username=self.full_name_or_username,
391 full_name_or_username=self.full_name_or_username,
392 short_contact=self.short_contact,
392 short_contact=self.short_contact,
393 full_contact=self.full_contact
393 full_contact=self.full_contact
394 )
394 )
395
395
396
396
397 class UserLog(Base, BaseModel):
397 class UserLog(Base, BaseModel):
398 __tablename__ = 'user_logs'
398 __tablename__ = 'user_logs'
399 __table_args__ = (
399 __table_args__ = (
400 {'extend_existing': True, 'mysql_engine':'InnoDB',
400 {'extend_existing': True, 'mysql_engine':'InnoDB',
401 'mysql_charset': 'utf8'},
401 'mysql_charset': 'utf8'},
402 )
402 )
403 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
403 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
404 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
404 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
405 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
405 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
406 repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None)
406 repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None)
407 user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None)
407 user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None)
408 action = Column("action", String(1200000), nullable=True, unique=None, default=None)
408 action = Column("action", String(1200000), nullable=True, unique=None, default=None)
409 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
409 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
410
410
411 @property
411 @property
412 def action_as_day(self):
412 def action_as_day(self):
413 return datetime.date(*self.action_date.timetuple()[:3])
413 return datetime.date(*self.action_date.timetuple()[:3])
414
414
415 user = relationship('User')
415 user = relationship('User')
416 repository = relationship('Repository', cascade='')
416 repository = relationship('Repository', cascade='')
417
417
418
418
419 class UserGroup(Base, BaseModel):
419 class UserGroup(Base, BaseModel):
420 __tablename__ = 'users_groups'
420 __tablename__ = 'users_groups'
421 __table_args__ = (
421 __table_args__ = (
422 {'extend_existing': True, 'mysql_engine':'InnoDB',
422 {'extend_existing': True, 'mysql_engine':'InnoDB',
423 'mysql_charset': 'utf8'},
423 'mysql_charset': 'utf8'},
424 )
424 )
425
425
426 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
426 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
427 users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None)
427 users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None)
428 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
428 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
429
429
430 members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
430 members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
431 users_group_to_perm = relationship('UserGroupToPerm', cascade='all')
431 users_group_to_perm = relationship('UserGroupToPerm', cascade='all')
432 users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
432 users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
433
433
434 def __unicode__(self):
434 def __unicode__(self):
435 return u'<userGroup(%s)>' % (self.users_group_name)
435 return u'<userGroup(%s)>' % (self.users_group_name)
436
436
437 @classmethod
437 @classmethod
438 def get_by_group_name(cls, group_name, cache=False,
438 def get_by_group_name(cls, group_name, cache=False,
439 case_insensitive=False):
439 case_insensitive=False):
440 if case_insensitive:
440 if case_insensitive:
441 q = cls.query().filter(cls.users_group_name.ilike(group_name))
441 q = cls.query().filter(cls.users_group_name.ilike(group_name))
442 else:
442 else:
443 q = cls.query().filter(cls.users_group_name == group_name)
443 q = cls.query().filter(cls.users_group_name == group_name)
444 if cache:
444 if cache:
445 q = q.options(FromCache(
445 q = q.options(FromCache(
446 "sql_cache_short",
446 "sql_cache_short",
447 "get_user_%s" % _hash_key(group_name)
447 "get_user_%s" % _hash_key(group_name)
448 )
448 )
449 )
449 )
450 return q.scalar()
450 return q.scalar()
451
451
452 @classmethod
452 @classmethod
453 def get(cls, users_group_id, cache=False):
453 def get(cls, users_group_id, cache=False):
454 users_group = cls.query()
454 users_group = cls.query()
455 if cache:
455 if cache:
456 users_group = users_group.options(FromCache("sql_cache_short",
456 users_group = users_group.options(FromCache("sql_cache_short",
457 "get_users_group_%s" % users_group_id))
457 "get_users_group_%s" % users_group_id))
458 return users_group.get(users_group_id)
458 return users_group.get(users_group_id)
459
459
460
460
461 class UserGroupMember(Base, BaseModel):
461 class UserGroupMember(Base, BaseModel):
462 __tablename__ = 'users_groups_members'
462 __tablename__ = 'users_groups_members'
463 __table_args__ = (
463 __table_args__ = (
464 {'extend_existing': True, 'mysql_engine':'InnoDB',
464 {'extend_existing': True, 'mysql_engine':'InnoDB',
465 'mysql_charset': 'utf8'},
465 'mysql_charset': 'utf8'},
466 )
466 )
467
467
468 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
468 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
469 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
469 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
470 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
470 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
471
471
472 user = relationship('User', lazy='joined')
472 user = relationship('User', lazy='joined')
473 users_group = relationship('UserGroup')
473 users_group = relationship('UserGroup')
474
474
475 def __init__(self, gr_id='', u_id=''):
475 def __init__(self, gr_id='', u_id=''):
476 self.users_group_id = gr_id
476 self.users_group_id = gr_id
477 self.user_id = u_id
477 self.user_id = u_id
478
478
479
479
480 class Repository(Base, BaseModel):
480 class Repository(Base, BaseModel):
481 __tablename__ = 'repositories'
481 __tablename__ = 'repositories'
482 __table_args__ = (
482 __table_args__ = (
483 UniqueConstraint('repo_name'),
483 UniqueConstraint('repo_name'),
484 {'extend_existing': True, 'mysql_engine':'InnoDB',
484 {'extend_existing': True, 'mysql_engine':'InnoDB',
485 'mysql_charset': 'utf8'},
485 'mysql_charset': 'utf8'},
486 )
486 )
487
487
488 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
488 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
489 repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None)
489 repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None)
490 clone_uri = Column("clone_uri", String(255), nullable=True, unique=False, default=None)
490 clone_uri = Column("clone_uri", String(255), nullable=True, unique=False, default=None)
491 repo_type = Column("repo_type", String(255), nullable=False, unique=False, default='hg')
491 repo_type = Column("repo_type", String(255), nullable=False, unique=False, default='hg')
492 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
492 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
493 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
493 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
494 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
494 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
495 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
495 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
496 description = Column("description", String(10000), nullable=True, unique=None, default=None)
496 description = Column("description", String(10000), nullable=True, unique=None, default=None)
497 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
497 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
498
498
499 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
499 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
500 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
500 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
501
501
502 user = relationship('User')
502 user = relationship('User')
503 fork = relationship('Repository', remote_side=repo_id)
503 fork = relationship('Repository', remote_side=repo_id)
504 group = relationship('RepoGroup')
504 group = relationship('RepoGroup')
505 repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
505 repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
506 users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
506 users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
507 stats = relationship('Statistics', cascade='all', uselist=False)
507 stats = relationship('Statistics', cascade='all', uselist=False)
508
508
509 followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all')
509 followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all')
510
510
511 logs = relationship('UserLog')
511 logs = relationship('UserLog')
512
512
513 def __unicode__(self):
513 def __unicode__(self):
514 return u"<%s('%s:%s')>" % (self.__class__.__name__,self.repo_id,
514 return u"<%s('%s:%s')>" % (self.__class__.__name__,self.repo_id,
515 self.repo_name)
515 self.repo_name)
516
516
517 @classmethod
517 @classmethod
518 def url_sep(cls):
518 def url_sep(cls):
519 return '/'
519 return '/'
520
520
521 @classmethod
521 @classmethod
522 def get_by_repo_name(cls, repo_name):
522 def get_by_repo_name(cls, repo_name):
523 q = Session.query(cls).filter(cls.repo_name == repo_name)
523 q = Session.query(cls).filter(cls.repo_name == repo_name)
524 q = q.options(joinedload(Repository.fork))\
524 q = q.options(joinedload(Repository.fork))\
525 .options(joinedload(Repository.user))\
525 .options(joinedload(Repository.user))\
526 .options(joinedload(Repository.group))
526 .options(joinedload(Repository.group))
527 return q.scalar()
527 return q.scalar()
528
528
529 @classmethod
529 @classmethod
530 def get_repo_forks(cls, repo_id):
530 def get_repo_forks(cls, repo_id):
531 return cls.query().filter(Repository.fork_id == repo_id)
531 return cls.query().filter(Repository.fork_id == repo_id)
532
532
533 @classmethod
533 @classmethod
534 def base_path(cls):
534 def base_path(cls):
535 """
535 """
536 Returns base path when all repos are stored
536 Returns base path when all repos are stored
537
537
538 :param cls:
538 :param cls:
539 """
539 """
540 q = Session.query(RhodeCodeUi)\
540 q = Session.query(RhodeCodeUi)\
541 .filter(RhodeCodeUi.ui_key == cls.url_sep())
541 .filter(RhodeCodeUi.ui_key == cls.url_sep())
542 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
542 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
543 return q.one().ui_value
543 return q.one().ui_value
544
544
545 @property
545 @property
546 def just_name(self):
546 def just_name(self):
547 return self.repo_name.split(Repository.url_sep())[-1]
547 return self.repo_name.split(Repository.url_sep())[-1]
548
548
549 @property
549 @property
550 def groups_with_parents(self):
550 def groups_with_parents(self):
551 groups = []
551 groups = []
552 if self.group is None:
552 if self.group is None:
553 return groups
553 return groups
554
554
555 cur_gr = self.group
555 cur_gr = self.group
556 groups.insert(0, cur_gr)
556 groups.insert(0, cur_gr)
557 while 1:
557 while 1:
558 gr = getattr(cur_gr, 'parent_group', None)
558 gr = getattr(cur_gr, 'parent_group', None)
559 cur_gr = cur_gr.parent_group
559 cur_gr = cur_gr.parent_group
560 if gr is None:
560 if gr is None:
561 break
561 break
562 groups.insert(0, gr)
562 groups.insert(0, gr)
563
563
564 return groups
564 return groups
565
565
566 @property
566 @property
567 def groups_and_repo(self):
567 def groups_and_repo(self):
568 return self.groups_with_parents, self.just_name
568 return self.groups_with_parents, self.just_name
569
569
570 @LazyProperty
570 @LazyProperty
571 def repo_path(self):
571 def repo_path(self):
572 """
572 """
573 Returns base full path for that repository means where it actually
573 Returns base full path for that repository means where it actually
574 exists on a filesystem
574 exists on a filesystem
575 """
575 """
576 q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key ==
576 q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key ==
577 Repository.url_sep())
577 Repository.url_sep())
578 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
578 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
579 return q.one().ui_value
579 return q.one().ui_value
580
580
581 @property
581 @property
582 def repo_full_path(self):
582 def repo_full_path(self):
583 p = [self.repo_path]
583 p = [self.repo_path]
584 # we need to split the name by / since this is how we store the
584 # we need to split the name by / since this is how we store the
585 # names in the database, but that eventually needs to be converted
585 # names in the database, but that eventually needs to be converted
586 # into a valid system path
586 # into a valid system path
587 p += self.repo_name.split(Repository.url_sep())
587 p += self.repo_name.split(Repository.url_sep())
588 return os.path.join(*p)
588 return os.path.join(*p)
589
589
590 def get_new_name(self, repo_name):
590 def get_new_name(self, repo_name):
591 """
591 """
592 returns new full repository name based on assigned group and new new
592 returns new full repository name based on assigned group and new new
593
593
594 :param group_name:
594 :param group_name:
595 """
595 """
596 path_prefix = self.group.full_path_splitted if self.group else []
596 path_prefix = self.group.full_path_splitted if self.group else []
597 return Repository.url_sep().join(path_prefix + [repo_name])
597 return Repository.url_sep().join(path_prefix + [repo_name])
598
598
599 @property
599 @property
600 def _config(self):
600 def _config(self):
601 """
601 """
602 Returns db based config object.
602 Returns db based config object.
603 """
603 """
604 from rhodecode.lib.utils import make_db_config
604 from rhodecode.lib.utils import make_db_config
605 return make_db_config(clear_session=False)
605 return make_db_config(clear_session=False)
606
606
607 @classmethod
607 @classmethod
608 def is_valid(cls, repo_name):
608 def is_valid(cls, repo_name):
609 """
609 """
610 returns True if given repo name is a valid filesystem repository
610 returns True if given repo name is a valid filesystem repository
611
611
612 :param cls:
612 :param cls:
613 :param repo_name:
613 :param repo_name:
614 """
614 """
615 from rhodecode.lib.utils import is_valid_repo
615 from rhodecode.lib.utils import is_valid_repo
616
616
617 return is_valid_repo(repo_name, cls.base_path())
617 return is_valid_repo(repo_name, cls.base_path())
618
618
619 #==========================================================================
619 #==========================================================================
620 # SCM PROPERTIES
620 # SCM PROPERTIES
621 #==========================================================================
621 #==========================================================================
622
622
623 def get_commit(self, rev):
623 def get_commit(self, rev):
624 return get_commit_safe(self.scm_instance, rev)
624 return get_commit_safe(self.scm_instance, rev)
625
625
626 @property
626 @property
627 def tip(self):
627 def tip(self):
628 return self.get_commit('tip')
628 return self.get_commit('tip')
629
629
630 @property
630 @property
631 def author(self):
631 def author(self):
632 return self.tip.author
632 return self.tip.author
633
633
634 @property
634 @property
635 def last_change(self):
635 def last_change(self):
636 return self.scm_instance.last_change
636 return self.scm_instance.last_change
637
637
638 def comments(self, revisions=None):
638 def comments(self, revisions=None):
639 """
639 """
640 Returns comments for this repository grouped by revisions
640 Returns comments for this repository grouped by revisions
641
641
642 :param revisions: filter query by revisions only
642 :param revisions: filter query by revisions only
643 """
643 """
644 cmts = ChangesetComment.query()\
644 cmts = ChangesetComment.query()\
645 .filter(ChangesetComment.repo == self)
645 .filter(ChangesetComment.repo == self)
646 if revisions:
646 if revisions:
647 cmts = cmts.filter(ChangesetComment.revision.in_(revisions))
647 cmts = cmts.filter(ChangesetComment.revision.in_(revisions))
648 grouped = defaultdict(list)
648 grouped = defaultdict(list)
649 for cmt in cmts.all():
649 for cmt in cmts.all():
650 grouped[cmt.revision].append(cmt)
650 grouped[cmt.revision].append(cmt)
651 return grouped
651 return grouped
652
652
653 #==========================================================================
653 #==========================================================================
654 # SCM CACHE INSTANCE
654 # SCM CACHE INSTANCE
655 #==========================================================================
655 #==========================================================================
656
656
657 @property
657 @property
658 def invalidate(self):
658 def invalidate(self):
659 return CacheInvalidation.invalidate(self.repo_name)
659 return CacheInvalidation.invalidate(self.repo_name)
660
660
661 def set_invalidate(self):
661 def set_invalidate(self):
662 """
662 """
663 set a cache for invalidation for this instance
663 set a cache for invalidation for this instance
664 """
664 """
665 CacheInvalidation.set_invalidate(self.repo_name)
665 CacheInvalidation.set_invalidate(self.repo_name)
666
666
667 @LazyProperty
667 @LazyProperty
668 def scm_instance(self):
668 def scm_instance(self):
669 return self.__get_instance()
669 return self.__get_instance()
670
670
671 @property
671 @property
672 def scm_instance_cached(self):
672 def scm_instance_cached(self):
673 return self.__get_instance()
673 return self.__get_instance()
674
674
675 def __get_instance(self):
675 def __get_instance(self):
676 repo_full_path = self.repo_full_path
676 repo_full_path = self.repo_full_path
677 try:
677 try:
678 alias = get_scm(repo_full_path)[0]
678 alias = get_scm(repo_full_path)[0]
679 log.debug('Creating instance of %s repository', alias)
679 log.debug('Creating instance of %s repository', alias)
680 backend = get_backend(alias)
680 backend = get_backend(alias)
681 except VCSError:
681 except VCSError:
682 log.error(traceback.format_exc())
682 log.error(traceback.format_exc())
683 log.error('Perhaps this repository is in db and not in '
683 log.error('Perhaps this repository is in db and not in '
684 'filesystem run rescan repositories with '
684 'filesystem run rescan repositories with '
685 '"destroy old data " option from admin panel')
685 '"destroy old data " option from admin panel')
686 return
686 return
687
687
688 if alias == 'hg':
688 if alias == 'hg':
689
689
690 repo = backend(safe_str(repo_full_path), create=False,
690 repo = backend(safe_str(repo_full_path), create=False,
691 config=self._config)
691 config=self._config)
692 else:
692 else:
693 repo = backend(repo_full_path, create=False)
693 repo = backend(repo_full_path, create=False)
694
694
695 return repo
695 return repo
696
696
697
697
698 class RepoGroup(Base, BaseModel):
698 class RepoGroup(Base, BaseModel):
699 __tablename__ = 'groups'
699 __tablename__ = 'groups'
700 __table_args__ = (
700 __table_args__ = (
701 UniqueConstraint('group_name', 'group_parent_id'),
701 UniqueConstraint('group_name', 'group_parent_id'),
702 CheckConstraint('group_id != group_parent_id'),
703 {'extend_existing': True, 'mysql_engine':'InnoDB',
702 {'extend_existing': True, 'mysql_engine':'InnoDB',
704 'mysql_charset': 'utf8'},
703 'mysql_charset': 'utf8'},
705 )
704 )
706 __mapper_args__ = {'order_by': 'group_name'}
705 __mapper_args__ = {'order_by': 'group_name'}
707
706
708 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
707 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
709 group_name = Column("group_name", String(255), nullable=False, unique=True, default=None)
708 group_name = Column("group_name", String(255), nullable=False, unique=True, default=None)
710 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
709 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
711 group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None)
710 group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None)
712
711
713 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
712 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
714 users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
713 users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
715
714
716 parent_group = relationship('RepoGroup', remote_side=group_id)
715 parent_group = relationship('RepoGroup', remote_side=group_id)
717
716
718 def __init__(self, group_name='', parent_group=None):
717 def __init__(self, group_name='', parent_group=None):
719 self.group_name = group_name
718 self.group_name = group_name
720 self.parent_group = parent_group
719 self.parent_group = parent_group
721
720
722 def __unicode__(self):
721 def __unicode__(self):
723 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
722 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
724 self.group_name)
723 self.group_name)
725
724
726 @classmethod
725 @classmethod
727 def url_sep(cls):
726 def url_sep(cls):
728 return '/'
727 return '/'
729
728
730 @classmethod
729 @classmethod
731 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
730 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
732 if case_insensitive:
731 if case_insensitive:
733 gr = cls.query()\
732 gr = cls.query()\
734 .filter(cls.group_name.ilike(group_name))
733 .filter(cls.group_name.ilike(group_name))
735 else:
734 else:
736 gr = cls.query()\
735 gr = cls.query()\
737 .filter(cls.group_name == group_name)
736 .filter(cls.group_name == group_name)
738 if cache:
737 if cache:
739 gr = gr.options(FromCache(
738 gr = gr.options(FromCache(
740 "sql_cache_short",
739 "sql_cache_short",
741 "get_group_%s" % _hash_key(group_name)
740 "get_group_%s" % _hash_key(group_name)
742 )
741 )
743 )
742 )
744 return gr.scalar()
743 return gr.scalar()
745
744
746 @property
745 @property
747 def parents(self):
746 def parents(self):
748 parents_recursion_limit = 5
747 parents_recursion_limit = 5
749 groups = []
748 groups = []
750 if self.parent_group is None:
749 if self.parent_group is None:
751 return groups
750 return groups
752 cur_gr = self.parent_group
751 cur_gr = self.parent_group
753 groups.insert(0, cur_gr)
752 groups.insert(0, cur_gr)
754 cnt = 0
753 cnt = 0
755 while 1:
754 while 1:
756 cnt += 1
755 cnt += 1
757 gr = getattr(cur_gr, 'parent_group', None)
756 gr = getattr(cur_gr, 'parent_group', None)
758 cur_gr = cur_gr.parent_group
757 cur_gr = cur_gr.parent_group
759 if gr is None:
758 if gr is None:
760 break
759 break
761 if cnt == parents_recursion_limit:
760 if cnt == parents_recursion_limit:
762 # this will prevent accidental infinit loops
761 # this will prevent accidental infinit loops
763 log.error('group nested more than %s', parents_recursion_limit)
762 log.error('group nested more than %s', parents_recursion_limit)
764 break
763 break
765
764
766 groups.insert(0, gr)
765 groups.insert(0, gr)
767 return groups
766 return groups
768
767
769 @property
768 @property
770 def children(self):
769 def children(self):
771 return RepoGroup.query().filter(RepoGroup.parent_group == self)
770 return RepoGroup.query().filter(RepoGroup.parent_group == self)
772
771
773 @property
772 @property
774 def name(self):
773 def name(self):
775 return self.group_name.split(RepoGroup.url_sep())[-1]
774 return self.group_name.split(RepoGroup.url_sep())[-1]
776
775
777 @property
776 @property
778 def full_path(self):
777 def full_path(self):
779 return self.group_name
778 return self.group_name
780
779
781 @property
780 @property
782 def full_path_splitted(self):
781 def full_path_splitted(self):
783 return self.group_name.split(RepoGroup.url_sep())
782 return self.group_name.split(RepoGroup.url_sep())
784
783
785 @property
784 @property
786 def repositories(self):
785 def repositories(self):
787 return Repository.query()\
786 return Repository.query()\
788 .filter(Repository.group == self)\
787 .filter(Repository.group == self)\
789 .order_by(Repository.repo_name)
788 .order_by(Repository.repo_name)
790
789
791 @property
790 @property
792 def repositories_recursive_count(self):
791 def repositories_recursive_count(self):
793 cnt = self.repositories.count()
792 cnt = self.repositories.count()
794
793
795 def children_count(group):
794 def children_count(group):
796 cnt = 0
795 cnt = 0
797 for child in group.children:
796 for child in group.children:
798 cnt += child.repositories.count()
797 cnt += child.repositories.count()
799 cnt += children_count(child)
798 cnt += children_count(child)
800 return cnt
799 return cnt
801
800
802 return cnt + children_count(self)
801 return cnt + children_count(self)
803
802
804 def get_new_name(self, group_name):
803 def get_new_name(self, group_name):
805 """
804 """
806 returns new full group name based on parent and new name
805 returns new full group name based on parent and new name
807
806
808 :param group_name:
807 :param group_name:
809 """
808 """
810 path_prefix = (self.parent_group.full_path_splitted if
809 path_prefix = (self.parent_group.full_path_splitted if
811 self.parent_group else [])
810 self.parent_group else [])
812 return RepoGroup.url_sep().join(path_prefix + [group_name])
811 return RepoGroup.url_sep().join(path_prefix + [group_name])
813
812
814
813
815 class Permission(Base, BaseModel):
814 class Permission(Base, BaseModel):
816 __tablename__ = 'permissions'
815 __tablename__ = 'permissions'
817 __table_args__ = (
816 __table_args__ = (
818 {'extend_existing': True, 'mysql_engine':'InnoDB',
817 {'extend_existing': True, 'mysql_engine':'InnoDB',
819 'mysql_charset': 'utf8'},
818 'mysql_charset': 'utf8'},
820 )
819 )
821 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
820 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
822 permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None)
821 permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None)
823 permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None)
822 permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None)
824
823
825 def __unicode__(self):
824 def __unicode__(self):
826 return u"<%s('%s:%s')>" % (
825 return u"<%s('%s:%s')>" % (
827 self.__class__.__name__, self.permission_id, self.permission_name
826 self.__class__.__name__, self.permission_id, self.permission_name
828 )
827 )
829
828
830 @classmethod
829 @classmethod
831 def get_by_key(cls, key):
830 def get_by_key(cls, key):
832 return cls.query().filter(cls.permission_name == key).scalar()
831 return cls.query().filter(cls.permission_name == key).scalar()
833
832
834 @classmethod
833 @classmethod
835 def get_default_repo_perms(cls, default_user_id):
834 def get_default_repo_perms(cls, default_user_id):
836 q = Session.query(UserRepoToPerm, Repository, cls)\
835 q = Session.query(UserRepoToPerm, Repository, cls)\
837 .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
836 .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
838 .join((cls, UserRepoToPerm.permission_id == cls.permission_id))\
837 .join((cls, UserRepoToPerm.permission_id == cls.permission_id))\
839 .filter(UserRepoToPerm.user_id == default_user_id)
838 .filter(UserRepoToPerm.user_id == default_user_id)
840
839
841 return q.all()
840 return q.all()
842
841
843 @classmethod
842 @classmethod
844 def get_default_group_perms(cls, default_user_id):
843 def get_default_group_perms(cls, default_user_id):
845 q = Session.query(UserRepoGroupToPerm, RepoGroup, cls)\
844 q = Session.query(UserRepoGroupToPerm, RepoGroup, cls)\
846 .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
845 .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
847 .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id))\
846 .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id))\
848 .filter(UserRepoGroupToPerm.user_id == default_user_id)
847 .filter(UserRepoGroupToPerm.user_id == default_user_id)
849
848
850 return q.all()
849 return q.all()
851
850
852
851
853 class UserRepoToPerm(Base, BaseModel):
852 class UserRepoToPerm(Base, BaseModel):
854 __tablename__ = 'repo_to_perm'
853 __tablename__ = 'repo_to_perm'
855 __table_args__ = (
854 __table_args__ = (
856 UniqueConstraint('user_id', 'repository_id', 'permission_id'),
855 UniqueConstraint('user_id', 'repository_id', 'permission_id'),
857 {'extend_existing': True, 'mysql_engine':'InnoDB',
856 {'extend_existing': True, 'mysql_engine':'InnoDB',
858 'mysql_charset': 'utf8'}
857 'mysql_charset': 'utf8'}
859 )
858 )
860 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
859 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
861 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
860 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
862 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
861 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
863 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
862 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
864
863
865 user = relationship('User')
864 user = relationship('User')
866 repository = relationship('Repository')
865 repository = relationship('Repository')
867 permission = relationship('Permission')
866 permission = relationship('Permission')
868
867
869 @classmethod
868 @classmethod
870 def create(cls, user, repository, permission):
869 def create(cls, user, repository, permission):
871 n = cls()
870 n = cls()
872 n.user = user
871 n.user = user
873 n.repository = repository
872 n.repository = repository
874 n.permission = permission
873 n.permission = permission
875 Session.add(n)
874 Session.add(n)
876 return n
875 return n
877
876
878 def __unicode__(self):
877 def __unicode__(self):
879 return u'<user:%s => %s >' % (self.user, self.repository)
878 return u'<user:%s => %s >' % (self.user, self.repository)
880
879
881
880
882 class UserToPerm(Base, BaseModel):
881 class UserToPerm(Base, BaseModel):
883 __tablename__ = 'user_to_perm'
882 __tablename__ = 'user_to_perm'
884 __table_args__ = (
883 __table_args__ = (
885 UniqueConstraint('user_id', 'permission_id'),
884 UniqueConstraint('user_id', 'permission_id'),
886 {'extend_existing': True, 'mysql_engine':'InnoDB',
885 {'extend_existing': True, 'mysql_engine':'InnoDB',
887 'mysql_charset': 'utf8'}
886 'mysql_charset': 'utf8'}
888 )
887 )
889 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
888 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
890 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
889 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
891 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
890 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
892
891
893 user = relationship('User')
892 user = relationship('User')
894 permission = relationship('Permission', lazy='joined')
893 permission = relationship('Permission', lazy='joined')
895
894
896
895
897 class UserGroupRepoToPerm(Base, BaseModel):
896 class UserGroupRepoToPerm(Base, BaseModel):
898 __tablename__ = 'users_group_repo_to_perm'
897 __tablename__ = 'users_group_repo_to_perm'
899 __table_args__ = (
898 __table_args__ = (
900 UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
899 UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
901 {'extend_existing': True, 'mysql_engine':'InnoDB',
900 {'extend_existing': True, 'mysql_engine':'InnoDB',
902 'mysql_charset': 'utf8'}
901 'mysql_charset': 'utf8'}
903 )
902 )
904 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
903 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
905 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
904 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
906 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
905 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
907 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
906 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
908
907
909 users_group = relationship('UserGroup')
908 users_group = relationship('UserGroup')
910 permission = relationship('Permission')
909 permission = relationship('Permission')
911 repository = relationship('Repository')
910 repository = relationship('Repository')
912
911
913 @classmethod
912 @classmethod
914 def create(cls, users_group, repository, permission):
913 def create(cls, users_group, repository, permission):
915 n = cls()
914 n = cls()
916 n.users_group = users_group
915 n.users_group = users_group
917 n.repository = repository
916 n.repository = repository
918 n.permission = permission
917 n.permission = permission
919 Session.add(n)
918 Session.add(n)
920 return n
919 return n
921
920
922 def __unicode__(self):
921 def __unicode__(self):
923 return u'<userGroup:%s => %s >' % (self.users_group, self.repository)
922 return u'<userGroup:%s => %s >' % (self.users_group, self.repository)
924
923
925
924
926 class UserGroupToPerm(Base, BaseModel):
925 class UserGroupToPerm(Base, BaseModel):
927 __tablename__ = 'users_group_to_perm'
926 __tablename__ = 'users_group_to_perm'
928 __table_args__ = (
927 __table_args__ = (
929 UniqueConstraint('users_group_id', 'permission_id',),
928 UniqueConstraint('users_group_id', 'permission_id',),
930 {'extend_existing': True, 'mysql_engine':'InnoDB',
929 {'extend_existing': True, 'mysql_engine':'InnoDB',
931 'mysql_charset': 'utf8'}
930 'mysql_charset': 'utf8'}
932 )
931 )
933 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
932 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
934 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
933 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
935 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
934 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
936
935
937 users_group = relationship('UserGroup')
936 users_group = relationship('UserGroup')
938 permission = relationship('Permission')
937 permission = relationship('Permission')
939
938
940
939
941 class UserRepoGroupToPerm(Base, BaseModel):
940 class UserRepoGroupToPerm(Base, BaseModel):
942 __tablename__ = 'user_repo_group_to_perm'
941 __tablename__ = 'user_repo_group_to_perm'
943 __table_args__ = (
942 __table_args__ = (
944 UniqueConstraint('user_id', 'group_id', 'permission_id'),
943 UniqueConstraint('user_id', 'group_id', 'permission_id'),
945 {'extend_existing': True, 'mysql_engine':'InnoDB',
944 {'extend_existing': True, 'mysql_engine':'InnoDB',
946 'mysql_charset': 'utf8'}
945 'mysql_charset': 'utf8'}
947 )
946 )
948
947
949 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
948 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
950 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
949 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
951 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
950 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
952 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
951 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
953
952
954 user = relationship('User')
953 user = relationship('User')
955 group = relationship('RepoGroup')
954 group = relationship('RepoGroup')
956 permission = relationship('Permission')
955 permission = relationship('Permission')
957
956
958
957
959 class UserGroupRepoGroupToPerm(Base, BaseModel):
958 class UserGroupRepoGroupToPerm(Base, BaseModel):
960 __tablename__ = 'users_group_repo_group_to_perm'
959 __tablename__ = 'users_group_repo_group_to_perm'
961 __table_args__ = (
960 __table_args__ = (
962 UniqueConstraint('users_group_id', 'group_id'),
961 UniqueConstraint('users_group_id', 'group_id'),
963 {'extend_existing': True, 'mysql_engine':'InnoDB',
962 {'extend_existing': True, 'mysql_engine':'InnoDB',
964 'mysql_charset': 'utf8'}
963 'mysql_charset': 'utf8'}
965 )
964 )
966
965
967 users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
966 users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
968 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
967 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
969 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
968 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
970 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
969 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
971
970
972 users_group = relationship('UserGroup')
971 users_group = relationship('UserGroup')
973 permission = relationship('Permission')
972 permission = relationship('Permission')
974 group = relationship('RepoGroup')
973 group = relationship('RepoGroup')
975
974
976
975
977 class Statistics(Base, BaseModel):
976 class Statistics(Base, BaseModel):
978 __tablename__ = 'statistics'
977 __tablename__ = 'statistics'
979 __table_args__ = (
978 __table_args__ = (
980 UniqueConstraint('repository_id'),
979 UniqueConstraint('repository_id'),
981 {'extend_existing': True, 'mysql_engine':'InnoDB',
980 {'extend_existing': True, 'mysql_engine':'InnoDB',
982 'mysql_charset': 'utf8'}
981 'mysql_charset': 'utf8'}
983 )
982 )
984 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
983 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
985 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
984 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
986 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
985 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
987 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
986 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
988 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
987 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
989 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
988 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
990
989
991 repository = relationship('Repository', single_parent=True)
990 repository = relationship('Repository', single_parent=True)
992
991
993
992
994 class UserFollowing(Base, BaseModel):
993 class UserFollowing(Base, BaseModel):
995 __tablename__ = 'user_followings'
994 __tablename__ = 'user_followings'
996 __table_args__ = (
995 __table_args__ = (
997 UniqueConstraint('user_id', 'follows_repository_id'),
996 UniqueConstraint('user_id', 'follows_repository_id'),
998 UniqueConstraint('user_id', 'follows_user_id'),
997 UniqueConstraint('user_id', 'follows_user_id'),
999 {'extend_existing': True, 'mysql_engine':'InnoDB',
998 {'extend_existing': True, 'mysql_engine':'InnoDB',
1000 'mysql_charset': 'utf8'}
999 'mysql_charset': 'utf8'}
1001 )
1000 )
1002
1001
1003 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1002 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1004 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1003 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1005 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
1004 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
1006 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
1005 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
1007 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
1006 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
1008
1007
1009 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
1008 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
1010
1009
1011 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
1010 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
1012 follows_repository = relationship('Repository', order_by='Repository.repo_name')
1011 follows_repository = relationship('Repository', order_by='Repository.repo_name')
1013
1012
1014 @classmethod
1013 @classmethod
1015 def get_repo_followers(cls, repo_id):
1014 def get_repo_followers(cls, repo_id):
1016 return cls.query().filter(cls.follows_repo_id == repo_id)
1015 return cls.query().filter(cls.follows_repo_id == repo_id)
1017
1016
1018
1017
1019 class CacheInvalidation(Base, BaseModel):
1018 class CacheInvalidation(Base, BaseModel):
1020 __tablename__ = 'cache_invalidation'
1019 __tablename__ = 'cache_invalidation'
1021 __table_args__ = (
1020 __table_args__ = (
1022 UniqueConstraint('cache_key'),
1021 UniqueConstraint('cache_key'),
1023 {'extend_existing': True, 'mysql_engine':'InnoDB',
1022 {'extend_existing': True, 'mysql_engine':'InnoDB',
1024 'mysql_charset': 'utf8'},
1023 'mysql_charset': 'utf8'},
1025 )
1024 )
1026 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1025 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1027 cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None)
1026 cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None)
1028 cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None)
1027 cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None)
1029 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
1028 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
1030
1029
1031 def __init__(self, cache_key, cache_args=''):
1030 def __init__(self, cache_key, cache_args=''):
1032 self.cache_key = cache_key
1031 self.cache_key = cache_key
1033 self.cache_args = cache_args
1032 self.cache_args = cache_args
1034 self.cache_active = False
1033 self.cache_active = False
1035
1034
1036 def __unicode__(self):
1035 def __unicode__(self):
1037 return u"<%s('%s:%s')>" % (self.__class__.__name__,
1036 return u"<%s('%s:%s')>" % (self.__class__.__name__,
1038 self.cache_id, self.cache_key)
1037 self.cache_id, self.cache_key)
1039
1038
1040 @classmethod
1039 @classmethod
1041 def _get_key(cls, key):
1040 def _get_key(cls, key):
1042 """
1041 """
1043 Wrapper for generating a key, together with a prefix
1042 Wrapper for generating a key, together with a prefix
1044
1043
1045 :param key:
1044 :param key:
1046 """
1045 """
1047 import rhodecode
1046 import rhodecode
1048 prefix = ''
1047 prefix = ''
1049 iid = rhodecode.CONFIG.get('instance_id')
1048 iid = rhodecode.CONFIG.get('instance_id')
1050 if iid:
1049 if iid:
1051 prefix = iid
1050 prefix = iid
1052 return "%s%s" % (prefix, key), prefix, key.rstrip('_README')
1051 return "%s%s" % (prefix, key), prefix, key.rstrip('_README')
1053
1052
1054 @classmethod
1053 @classmethod
1055 def get_by_key(cls, key):
1054 def get_by_key(cls, key):
1056 return cls.query().filter(cls.cache_key == key).scalar()
1055 return cls.query().filter(cls.cache_key == key).scalar()
1057
1056
1058 @classmethod
1057 @classmethod
1059 def _get_or_create_key(cls, key, prefix, org_key):
1058 def _get_or_create_key(cls, key, prefix, org_key):
1060 inv_obj = Session.query(cls).filter(cls.cache_key == key).scalar()
1059 inv_obj = Session.query(cls).filter(cls.cache_key == key).scalar()
1061 if not inv_obj:
1060 if not inv_obj:
1062 try:
1061 try:
1063 inv_obj = CacheInvalidation(key, org_key)
1062 inv_obj = CacheInvalidation(key, org_key)
1064 Session.add(inv_obj)
1063 Session.add(inv_obj)
1065 Session.commit()
1064 Session.commit()
1066 except Exception:
1065 except Exception:
1067 log.error(traceback.format_exc())
1066 log.error(traceback.format_exc())
1068 Session.rollback()
1067 Session.rollback()
1069 return inv_obj
1068 return inv_obj
1070
1069
1071 @classmethod
1070 @classmethod
1072 def invalidate(cls, key):
1071 def invalidate(cls, key):
1073 """
1072 """
1074 Returns Invalidation object if this given key should be invalidated
1073 Returns Invalidation object if this given key should be invalidated
1075 None otherwise. `cache_active = False` means that this cache
1074 None otherwise. `cache_active = False` means that this cache
1076 state is not valid and needs to be invalidated
1075 state is not valid and needs to be invalidated
1077
1076
1078 :param key:
1077 :param key:
1079 """
1078 """
1080
1079
1081 key, _prefix, _org_key = cls._get_key(key)
1080 key, _prefix, _org_key = cls._get_key(key)
1082 inv = cls._get_or_create_key(key, _prefix, _org_key)
1081 inv = cls._get_or_create_key(key, _prefix, _org_key)
1083
1082
1084 if inv and inv.cache_active is False:
1083 if inv and inv.cache_active is False:
1085 return inv
1084 return inv
1086
1085
1087 @classmethod
1086 @classmethod
1088 def set_invalidate(cls, key):
1087 def set_invalidate(cls, key):
1089 """
1088 """
1090 Mark this Cache key for invalidation
1089 Mark this Cache key for invalidation
1091
1090
1092 :param key:
1091 :param key:
1093 """
1092 """
1094
1093
1095 key, _prefix, _org_key = cls._get_key(key)
1094 key, _prefix, _org_key = cls._get_key(key)
1096 inv_objs = Session.query(cls).filter(cls.cache_args == _org_key).all()
1095 inv_objs = Session.query(cls).filter(cls.cache_args == _org_key).all()
1097 log.debug('marking %s key[s] %s for invalidation', len(inv_objs), _org_key)
1096 log.debug('marking %s key[s] %s for invalidation', len(inv_objs), _org_key)
1098 try:
1097 try:
1099 for inv_obj in inv_objs:
1098 for inv_obj in inv_objs:
1100 if inv_obj:
1099 if inv_obj:
1101 inv_obj.cache_active = False
1100 inv_obj.cache_active = False
1102
1101
1103 Session.add(inv_obj)
1102 Session.add(inv_obj)
1104 Session.commit()
1103 Session.commit()
1105 except Exception:
1104 except Exception:
1106 log.error(traceback.format_exc())
1105 log.error(traceback.format_exc())
1107 Session.rollback()
1106 Session.rollback()
1108
1107
1109 @classmethod
1108 @classmethod
1110 def set_valid(cls, key):
1109 def set_valid(cls, key):
1111 """
1110 """
1112 Mark this cache key as active and currently cached
1111 Mark this cache key as active and currently cached
1113
1112
1114 :param key:
1113 :param key:
1115 """
1114 """
1116 inv_obj = cls.get_by_key(key)
1115 inv_obj = cls.get_by_key(key)
1117 inv_obj.cache_active = True
1116 inv_obj.cache_active = True
1118 Session.add(inv_obj)
1117 Session.add(inv_obj)
1119 Session.commit()
1118 Session.commit()
1120
1119
1121
1120
1122 class ChangesetComment(Base, BaseModel):
1121 class ChangesetComment(Base, BaseModel):
1123 __tablename__ = 'changeset_comments'
1122 __tablename__ = 'changeset_comments'
1124 __table_args__ = (
1123 __table_args__ = (
1125 {'extend_existing': True, 'mysql_engine':'InnoDB',
1124 {'extend_existing': True, 'mysql_engine':'InnoDB',
1126 'mysql_charset': 'utf8'},
1125 'mysql_charset': 'utf8'},
1127 )
1126 )
1128 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
1127 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
1129 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1128 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1130 revision = Column('revision', String(40), nullable=False)
1129 revision = Column('revision', String(40), nullable=False)
1131 line_no = Column('line_no', Unicode(10), nullable=True)
1130 line_no = Column('line_no', Unicode(10), nullable=True)
1132 f_path = Column('f_path', Unicode(1000), nullable=True)
1131 f_path = Column('f_path', Unicode(1000), nullable=True)
1133 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
1132 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
1134 text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False)
1133 text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False)
1135 modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
1134 modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
1136
1135
1137 author = relationship('User', lazy='joined')
1136 author = relationship('User', lazy='joined')
1138 repo = relationship('Repository')
1137 repo = relationship('Repository')
1139
1138
1140 @classmethod
1139 @classmethod
1141 def get_users(cls, revision):
1140 def get_users(cls, revision):
1142 """
1141 """
1143 Returns user associated with this changesetComment. ie those
1142 Returns user associated with this changesetComment. ie those
1144 who actually commented
1143 who actually commented
1145
1144
1146 :param cls:
1145 :param cls:
1147 :param revision:
1146 :param revision:
1148 """
1147 """
1149 return Session.query(User)\
1148 return Session.query(User)\
1150 .filter(cls.revision == revision)\
1149 .filter(cls.revision == revision)\
1151 .join(ChangesetComment.author).all()
1150 .join(ChangesetComment.author).all()
1152
1151
1153
1152
1154 class Notification(Base, BaseModel):
1153 class Notification(Base, BaseModel):
1155 __tablename__ = 'notifications'
1154 __tablename__ = 'notifications'
1156 __table_args__ = (
1155 __table_args__ = (
1157 {'extend_existing': True, 'mysql_engine':'InnoDB',
1156 {'extend_existing': True, 'mysql_engine':'InnoDB',
1158 'mysql_charset': 'utf8'},
1157 'mysql_charset': 'utf8'},
1159 )
1158 )
1160
1159
1161 TYPE_CHANGESET_COMMENT = u'cs_comment'
1160 TYPE_CHANGESET_COMMENT = u'cs_comment'
1162 TYPE_MESSAGE = u'message'
1161 TYPE_MESSAGE = u'message'
1163 TYPE_MENTION = u'mention'
1162 TYPE_MENTION = u'mention'
1164 TYPE_REGISTRATION = u'registration'
1163 TYPE_REGISTRATION = u'registration'
1165
1164
1166 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
1165 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
1167 subject = Column('subject', Unicode(512), nullable=True)
1166 subject = Column('subject', Unicode(512), nullable=True)
1168 body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True)
1167 body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True)
1169 created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
1168 created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
1170 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1169 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1171 type_ = Column('type', Unicode(256))
1170 type_ = Column('type', Unicode(256))
1172
1171
1173 created_by_user = relationship('User')
1172 created_by_user = relationship('User')
1174 notifications_to_users = relationship('UserNotification', lazy='joined',
1173 notifications_to_users = relationship('UserNotification', lazy='joined',
1175 cascade="all, delete, delete-orphan")
1174 cascade="all, delete, delete-orphan")
1176
1175
1177 @property
1176 @property
1178 def recipients(self):
1177 def recipients(self):
1179 return [x.user for x in UserNotification.query()\
1178 return [x.user for x in UserNotification.query()\
1180 .filter(UserNotification.notification == self).all()]
1179 .filter(UserNotification.notification == self).all()]
1181
1180
1182 @classmethod
1181 @classmethod
1183 def create(cls, created_by, subject, body, recipients, type_=None):
1182 def create(cls, created_by, subject, body, recipients, type_=None):
1184 if type_ is None:
1183 if type_ is None:
1185 type_ = Notification.TYPE_MESSAGE
1184 type_ = Notification.TYPE_MESSAGE
1186
1185
1187 notification = cls()
1186 notification = cls()
1188 notification.created_by_user = created_by
1187 notification.created_by_user = created_by
1189 notification.subject = subject
1188 notification.subject = subject
1190 notification.body = body
1189 notification.body = body
1191 notification.type_ = type_
1190 notification.type_ = type_
1192 notification.created_on = datetime.datetime.now()
1191 notification.created_on = datetime.datetime.now()
1193
1192
1194 for u in recipients:
1193 for u in recipients:
1195 assoc = UserNotification()
1194 assoc = UserNotification()
1196 assoc.notification = notification
1195 assoc.notification = notification
1197 u.notifications.append(assoc)
1196 u.notifications.append(assoc)
1198 Session.add(notification)
1197 Session.add(notification)
1199 return notification
1198 return notification
1200
1199
1201 @property
1200 @property
1202 def description(self):
1201 def description(self):
1203 from rhodecode.model.notification import NotificationModel
1202 from rhodecode.model.notification import NotificationModel
1204 return NotificationModel().make_description(self)
1203 return NotificationModel().make_description(self)
1205
1204
1206
1205
1207 class UserNotification(Base, BaseModel):
1206 class UserNotification(Base, BaseModel):
1208 __tablename__ = 'user_to_notification'
1207 __tablename__ = 'user_to_notification'
1209 __table_args__ = (
1208 __table_args__ = (
1210 UniqueConstraint('user_id', 'notification_id'),
1209 UniqueConstraint('user_id', 'notification_id'),
1211 {'extend_existing': True, 'mysql_engine':'InnoDB',
1210 {'extend_existing': True, 'mysql_engine':'InnoDB',
1212 'mysql_charset': 'utf8'}
1211 'mysql_charset': 'utf8'}
1213 )
1212 )
1214 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
1213 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
1215 notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
1214 notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
1216 read = Column('read', Boolean, default=False)
1215 read = Column('read', Boolean, default=False)
1217 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
1216 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
1218
1217
1219 user = relationship('User', lazy="joined")
1218 user = relationship('User', lazy="joined")
1220 notification = relationship('Notification', lazy="joined",
1219 notification = relationship('Notification', lazy="joined",
1221 order_by=lambda: Notification.created_on.desc(),)
1220 order_by=lambda: Notification.created_on.desc(),)
1222
1221
1223 def mark_as_read(self):
1222 def mark_as_read(self):
1224 self.read = True
1223 self.read = True
1225 Session.add(self)
1224 Session.add(self)
1226
1225
1227
1226
1228 class DbMigrateVersion(Base, BaseModel):
1227 class DbMigrateVersion(Base, BaseModel):
1229 __tablename__ = 'db_migrate_version'
1228 __tablename__ = 'db_migrate_version'
1230 __table_args__ = (
1229 __table_args__ = (
1231 {'extend_existing': True, 'mysql_engine':'InnoDB',
1230 {'extend_existing': True, 'mysql_engine':'InnoDB',
1232 'mysql_charset': 'utf8'},
1231 'mysql_charset': 'utf8'},
1233 )
1232 )
1234 repository_id = Column('repository_id', String(250), primary_key=True)
1233 repository_id = Column('repository_id', String(250), primary_key=True)
1235 repository_path = Column('repository_path', Text)
1234 repository_path = Column('repository_path', Text)
1236 version = Column('version', Integer)
1235 version = Column('version', Integer)
1237
1236
1238 ## this is migration from 1_4_0, but now it's here to overcome a problem of
1237 ## this is migration from 1_4_0, but now it's here to overcome a problem of
1239 ## attaching a FK to this from 1_3_0 !
1238 ## attaching a FK to this from 1_3_0 !
1240
1239
1241
1240
1242 class PullRequest(Base, BaseModel):
1241 class PullRequest(Base, BaseModel):
1243 __tablename__ = 'pull_requests'
1242 __tablename__ = 'pull_requests'
1244 __table_args__ = (
1243 __table_args__ = (
1245 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1244 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1246 'mysql_charset': 'utf8'},
1245 'mysql_charset': 'utf8'},
1247 )
1246 )
1248
1247
1249 STATUS_NEW = u'new'
1248 STATUS_NEW = u'new'
1250 STATUS_OPEN = u'open'
1249 STATUS_OPEN = u'open'
1251 STATUS_CLOSED = u'closed'
1250 STATUS_CLOSED = u'closed'
1252
1251
1253 pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True)
1252 pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True)
1254 title = Column('title', Unicode(256), nullable=True)
1253 title = Column('title', Unicode(256), nullable=True)
1255 description = Column('description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), nullable=True)
1254 description = Column('description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), nullable=True)
1256 status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW)
1255 status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW)
1257 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1256 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1258 updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1257 updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1259 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1258 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1260 _revisions = Column('revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql')) # 500 revisions max
1259 _revisions = Column('revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql')) # 500 revisions max
1261 org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1260 org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1262 org_ref = Column('org_ref', Unicode(256), nullable=False)
1261 org_ref = Column('org_ref', Unicode(256), nullable=False)
1263 other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1262 other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1264 other_ref = Column('other_ref', Unicode(256), nullable=False)
1263 other_ref = Column('other_ref', Unicode(256), nullable=False)
@@ -1,972 +1,971 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2019 RhodeCode GmbH
3 # Copyright (C) 2010-2019 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21
21
22 import os
22 import os
23 import time
23 import time
24 import logging
24 import logging
25 import datetime
25 import datetime
26 import traceback
26 import traceback
27 import hashlib
27 import hashlib
28 import collections
28 import collections
29
29
30 from sqlalchemy import *
30 from sqlalchemy import *
31 from sqlalchemy.ext.hybrid import hybrid_property
31 from sqlalchemy.ext.hybrid import hybrid_property
32 from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
32 from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
33 from sqlalchemy.exc import DatabaseError
33 from sqlalchemy.exc import DatabaseError
34 from beaker.cache import cache_region, region_invalidate
34 from beaker.cache import cache_region, region_invalidate
35 from webob.exc import HTTPNotFound
35 from webob.exc import HTTPNotFound
36
36
37 from rhodecode.translation import _
37 from rhodecode.translation import _
38 from rhodecode.lib.vcs import get_backend
38 from rhodecode.lib.vcs import get_backend
39 from rhodecode.lib.vcs.utils.helpers import get_scm
39 from rhodecode.lib.vcs.utils.helpers import get_scm
40 from rhodecode.lib.vcs.exceptions import VCSError
40 from rhodecode.lib.vcs.exceptions import VCSError
41 from zope.cachedescriptors.property import Lazy as LazyProperty
41 from zope.cachedescriptors.property import Lazy as LazyProperty
42
42
43 from rhodecode.lib.utils2 import str2bool, safe_str, get_commit_safe, \
43 from rhodecode.lib.utils2 import str2bool, safe_str, get_commit_safe, \
44 safe_unicode, remove_suffix
44 safe_unicode, remove_suffix
45 from rhodecode.lib.ext_json import json
45 from rhodecode.lib.ext_json import json
46 from rhodecode.lib.caching_query import FromCache
46 from rhodecode.lib.caching_query import FromCache
47
47
48 from rhodecode.model.meta import Base, Session
48 from rhodecode.model.meta import Base, Session
49
49
50 URL_SEP = '/'
50 URL_SEP = '/'
51 log = logging.getLogger(__name__)
51 log = logging.getLogger(__name__)
52
52
53 #==============================================================================
53 #==============================================================================
54 # BASE CLASSES
54 # BASE CLASSES
55 #==============================================================================
55 #==============================================================================
56
56
57 _hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest()
57 _hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest()
58
58
59
59
60 class BaseModel(object):
60 class BaseModel(object):
61 """
61 """
62 Base Model for all classes
62 Base Model for all classes
63 """
63 """
64
64
65 @classmethod
65 @classmethod
66 def _get_keys(cls):
66 def _get_keys(cls):
67 """return column names for this model """
67 """return column names for this model """
68 return class_mapper(cls).c.keys()
68 return class_mapper(cls).c.keys()
69
69
70 def get_dict(self):
70 def get_dict(self):
71 """
71 """
72 return dict with keys and values corresponding
72 return dict with keys and values corresponding
73 to this model data """
73 to this model data """
74
74
75 d = {}
75 d = {}
76 for k in self._get_keys():
76 for k in self._get_keys():
77 d[k] = getattr(self, k)
77 d[k] = getattr(self, k)
78
78
79 # also use __json__() if present to get additional fields
79 # also use __json__() if present to get additional fields
80 _json_attr = getattr(self, '__json__', None)
80 _json_attr = getattr(self, '__json__', None)
81 if _json_attr:
81 if _json_attr:
82 # update with attributes from __json__
82 # update with attributes from __json__
83 if callable(_json_attr):
83 if callable(_json_attr):
84 _json_attr = _json_attr()
84 _json_attr = _json_attr()
85 for k, val in _json_attr.iteritems():
85 for k, val in _json_attr.iteritems():
86 d[k] = val
86 d[k] = val
87 return d
87 return d
88
88
89 def get_appstruct(self):
89 def get_appstruct(self):
90 """return list with keys and values tupples corresponding
90 """return list with keys and values tupples corresponding
91 to this model data """
91 to this model data """
92
92
93 l = []
93 l = []
94 for k in self._get_keys():
94 for k in self._get_keys():
95 l.append((k, getattr(self, k),))
95 l.append((k, getattr(self, k),))
96 return l
96 return l
97
97
98 def populate_obj(self, populate_dict):
98 def populate_obj(self, populate_dict):
99 """populate model with data from given populate_dict"""
99 """populate model with data from given populate_dict"""
100
100
101 for k in self._get_keys():
101 for k in self._get_keys():
102 if k in populate_dict:
102 if k in populate_dict:
103 setattr(self, k, populate_dict[k])
103 setattr(self, k, populate_dict[k])
104
104
105 @classmethod
105 @classmethod
106 def query(cls):
106 def query(cls):
107 return Session().query(cls)
107 return Session().query(cls)
108
108
109 @classmethod
109 @classmethod
110 def get(cls, id_):
110 def get(cls, id_):
111 if id_:
111 if id_:
112 return cls.query().get(id_)
112 return cls.query().get(id_)
113
113
114 @classmethod
114 @classmethod
115 def get_or_404(cls, id_):
115 def get_or_404(cls, id_):
116 try:
116 try:
117 id_ = int(id_)
117 id_ = int(id_)
118 except (TypeError, ValueError):
118 except (TypeError, ValueError):
119 raise HTTPNotFound
119 raise HTTPNotFound
120
120
121 res = cls.query().get(id_)
121 res = cls.query().get(id_)
122 if not res:
122 if not res:
123 raise HTTPNotFound
123 raise HTTPNotFound
124 return res
124 return res
125
125
126 @classmethod
126 @classmethod
127 def getAll(cls):
127 def getAll(cls):
128 return cls.query().all()
128 return cls.query().all()
129
129
130 @classmethod
130 @classmethod
131 def delete(cls, id_):
131 def delete(cls, id_):
132 obj = cls.query().get(id_)
132 obj = cls.query().get(id_)
133 Session().delete(obj)
133 Session().delete(obj)
134
134
135 def __repr__(self):
135 def __repr__(self):
136 if hasattr(self, '__unicode__'):
136 if hasattr(self, '__unicode__'):
137 # python repr needs to return str
137 # python repr needs to return str
138 return safe_str(self.__unicode__())
138 return safe_str(self.__unicode__())
139 return '<DB:%s>' % (self.__class__.__name__)
139 return '<DB:%s>' % (self.__class__.__name__)
140
140
141
141
142 class RhodeCodeSetting(Base, BaseModel):
142 class RhodeCodeSetting(Base, BaseModel):
143 __tablename__ = 'rhodecode_settings'
143 __tablename__ = 'rhodecode_settings'
144 __table_args__ = (
144 __table_args__ = (
145 UniqueConstraint('app_settings_name'),
145 UniqueConstraint('app_settings_name'),
146 {'extend_existing': True, 'mysql_engine': 'InnoDB',
146 {'extend_existing': True, 'mysql_engine': 'InnoDB',
147 'mysql_charset': 'utf8'}
147 'mysql_charset': 'utf8'}
148 )
148 )
149 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
149 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
150 app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None)
150 app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None)
151 _app_settings_value = Column("app_settings_value", String(255), nullable=True, unique=None, default=None)
151 _app_settings_value = Column("app_settings_value", String(255), nullable=True, unique=None, default=None)
152
152
153 def __init__(self, k='', v=''):
153 def __init__(self, k='', v=''):
154 self.app_settings_name = k
154 self.app_settings_name = k
155 self.app_settings_value = v
155 self.app_settings_value = v
156
156
157 @validates('_app_settings_value')
157 @validates('_app_settings_value')
158 def validate_settings_value(self, key, val):
158 def validate_settings_value(self, key, val):
159 assert type(val) == unicode
159 assert type(val) == unicode
160 return val
160 return val
161
161
162 @hybrid_property
162 @hybrid_property
163 def app_settings_value(self):
163 def app_settings_value(self):
164 v = self._app_settings_value
164 v = self._app_settings_value
165 if self.app_settings_name == 'ldap_active':
165 if self.app_settings_name == 'ldap_active':
166 v = str2bool(v)
166 v = str2bool(v)
167 return v
167 return v
168
168
169 @app_settings_value.setter
169 @app_settings_value.setter
170 def app_settings_value(self, val):
170 def app_settings_value(self, val):
171 """
171 """
172 Setter that will always make sure we use unicode in app_settings_value
172 Setter that will always make sure we use unicode in app_settings_value
173
173
174 :param val:
174 :param val:
175 """
175 """
176 self._app_settings_value = safe_unicode(val)
176 self._app_settings_value = safe_unicode(val)
177
177
178 def __unicode__(self):
178 def __unicode__(self):
179 return u"<%s('%s:%s')>" % (
179 return u"<%s('%s:%s')>" % (
180 self.__class__.__name__,
180 self.__class__.__name__,
181 self.app_settings_name, self.app_settings_value
181 self.app_settings_name, self.app_settings_value
182 )
182 )
183
183
184
184
185 class RhodeCodeUi(Base, BaseModel):
185 class RhodeCodeUi(Base, BaseModel):
186 __tablename__ = 'rhodecode_ui'
186 __tablename__ = 'rhodecode_ui'
187 __table_args__ = (
187 __table_args__ = (
188 UniqueConstraint('ui_key'),
188 UniqueConstraint('ui_key'),
189 {'extend_existing': True, 'mysql_engine': 'InnoDB',
189 {'extend_existing': True, 'mysql_engine': 'InnoDB',
190 'mysql_charset': 'utf8'}
190 'mysql_charset': 'utf8'}
191 )
191 )
192
192
193 HOOK_REPO_SIZE = 'changegroup.repo_size'
193 HOOK_REPO_SIZE = 'changegroup.repo_size'
194 HOOK_PUSH = 'changegroup.push_logger'
194 HOOK_PUSH = 'changegroup.push_logger'
195 HOOK_PRE_PUSH = 'prechangegroup.pre_push'
195 HOOK_PRE_PUSH = 'prechangegroup.pre_push'
196 HOOK_PULL = 'outgoing.pull_logger'
196 HOOK_PULL = 'outgoing.pull_logger'
197 HOOK_PRE_PULL = 'preoutgoing.pre_pull'
197 HOOK_PRE_PULL = 'preoutgoing.pre_pull'
198
198
199 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
199 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
200 ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None)
200 ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None)
201 ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None)
201 ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None)
202 ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None)
202 ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None)
203 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
203 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
204
204
205
205
206
206
207 class User(Base, BaseModel):
207 class User(Base, BaseModel):
208 __tablename__ = 'users'
208 __tablename__ = 'users'
209 __table_args__ = (
209 __table_args__ = (
210 UniqueConstraint('username'), UniqueConstraint('email'),
210 UniqueConstraint('username'), UniqueConstraint('email'),
211 Index('u_username_idx', 'username'),
211 Index('u_username_idx', 'username'),
212 Index('u_email_idx', 'email'),
212 Index('u_email_idx', 'email'),
213 {'extend_existing': True, 'mysql_engine': 'InnoDB',
213 {'extend_existing': True, 'mysql_engine': 'InnoDB',
214 'mysql_charset': 'utf8'}
214 'mysql_charset': 'utf8'}
215 )
215 )
216 DEFAULT_USER = 'default'
216 DEFAULT_USER = 'default'
217 DEFAULT_PERMISSIONS = [
217 DEFAULT_PERMISSIONS = [
218 'hg.register.manual_activate', 'hg.create.repository',
218 'hg.register.manual_activate', 'hg.create.repository',
219 'hg.fork.repository', 'repository.read', 'group.read'
219 'hg.fork.repository', 'repository.read', 'group.read'
220 ]
220 ]
221 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
221 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
222 username = Column("username", String(255), nullable=True, unique=None, default=None)
222 username = Column("username", String(255), nullable=True, unique=None, default=None)
223 password = Column("password", String(255), nullable=True, unique=None, default=None)
223 password = Column("password", String(255), nullable=True, unique=None, default=None)
224 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
224 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
225 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
225 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
226 name = Column("firstname", String(255), nullable=True, unique=None, default=None)
226 name = Column("firstname", String(255), nullable=True, unique=None, default=None)
227 lastname = Column("lastname", String(255), nullable=True, unique=None, default=None)
227 lastname = Column("lastname", String(255), nullable=True, unique=None, default=None)
228 _email = Column("email", String(255), nullable=True, unique=None, default=None)
228 _email = Column("email", String(255), nullable=True, unique=None, default=None)
229 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
229 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
230 ldap_dn = Column("ldap_dn", String(255), nullable=True, unique=None, default=None)
230 ldap_dn = Column("ldap_dn", String(255), nullable=True, unique=None, default=None)
231 api_key = Column("api_key", String(255), nullable=True, unique=None, default=None)
231 api_key = Column("api_key", String(255), nullable=True, unique=None, default=None)
232 inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
232 inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
233
233
234 user_log = relationship('UserLog', cascade='all')
234 user_log = relationship('UserLog', cascade='all')
235 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
235 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
236
236
237 repositories = relationship('Repository')
237 repositories = relationship('Repository')
238 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
238 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
239 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
239 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
240 repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all')
240 repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all')
241
241
242 group_member = relationship('UserGroupMember', cascade='all')
242 group_member = relationship('UserGroupMember', cascade='all')
243
243
244 notifications = relationship('UserNotification', cascade='all')
244 notifications = relationship('UserNotification', cascade='all')
245 # notifications assigned to this user
245 # notifications assigned to this user
246 user_created_notifications = relationship('Notification', cascade='all')
246 user_created_notifications = relationship('Notification', cascade='all')
247 # comments created by this user
247 # comments created by this user
248 user_comments = relationship('ChangesetComment', cascade='all')
248 user_comments = relationship('ChangesetComment', cascade='all')
249 user_emails = relationship('UserEmailMap', cascade='all')
249 user_emails = relationship('UserEmailMap', cascade='all')
250
250
251 @hybrid_property
251 @hybrid_property
252 def email(self):
252 def email(self):
253 return self._email
253 return self._email
254
254
255 @email.setter
255 @email.setter
256 def email(self, val):
256 def email(self, val):
257 self._email = val.lower() if val else None
257 self._email = val.lower() if val else None
258
258
259 @property
259 @property
260 def firstname(self):
260 def firstname(self):
261 # alias for future
261 # alias for future
262 return self.name
262 return self.name
263
263
264 @property
264 @property
265 def username_and_name(self):
265 def username_and_name(self):
266 return '%s (%s %s)' % (self.username, self.firstname, self.lastname)
266 return '%s (%s %s)' % (self.username, self.firstname, self.lastname)
267
267
268 @property
268 @property
269 def full_name(self):
269 def full_name(self):
270 return '%s %s' % (self.firstname, self.lastname)
270 return '%s %s' % (self.firstname, self.lastname)
271
271
272 @property
272 @property
273 def full_contact(self):
273 def full_contact(self):
274 return '%s %s <%s>' % (self.firstname, self.lastname, self.email)
274 return '%s %s <%s>' % (self.firstname, self.lastname, self.email)
275
275
276 @property
276 @property
277 def short_contact(self):
277 def short_contact(self):
278 return '%s %s' % (self.firstname, self.lastname)
278 return '%s %s' % (self.firstname, self.lastname)
279
279
280 @property
280 @property
281 def is_admin(self):
281 def is_admin(self):
282 return self.admin
282 return self.admin
283
283
284 @classmethod
284 @classmethod
285 def get_by_username(cls, username, case_insensitive=False, cache=False):
285 def get_by_username(cls, username, case_insensitive=False, cache=False):
286 if case_insensitive:
286 if case_insensitive:
287 q = cls.query().filter(cls.username.ilike(username))
287 q = cls.query().filter(cls.username.ilike(username))
288 else:
288 else:
289 q = cls.query().filter(cls.username == username)
289 q = cls.query().filter(cls.username == username)
290
290
291 if cache:
291 if cache:
292 q = q.options(FromCache(
292 q = q.options(FromCache(
293 "sql_cache_short",
293 "sql_cache_short",
294 "get_user_%s" % _hash_key(username)
294 "get_user_%s" % _hash_key(username)
295 )
295 )
296 )
296 )
297 return q.scalar()
297 return q.scalar()
298
298
299 @classmethod
299 @classmethod
300 def get_by_auth_token(cls, auth_token, cache=False):
300 def get_by_auth_token(cls, auth_token, cache=False):
301 q = cls.query().filter(cls.api_key == auth_token)
301 q = cls.query().filter(cls.api_key == auth_token)
302
302
303 if cache:
303 if cache:
304 q = q.options(FromCache("sql_cache_short",
304 q = q.options(FromCache("sql_cache_short",
305 "get_auth_token_%s" % auth_token))
305 "get_auth_token_%s" % auth_token))
306 return q.scalar()
306 return q.scalar()
307
307
308 @classmethod
308 @classmethod
309 def get_by_email(cls, email, case_insensitive=False, cache=False):
309 def get_by_email(cls, email, case_insensitive=False, cache=False):
310 if case_insensitive:
310 if case_insensitive:
311 q = cls.query().filter(cls.email.ilike(email))
311 q = cls.query().filter(cls.email.ilike(email))
312 else:
312 else:
313 q = cls.query().filter(cls.email == email)
313 q = cls.query().filter(cls.email == email)
314
314
315 if cache:
315 if cache:
316 q = q.options(FromCache("sql_cache_short",
316 q = q.options(FromCache("sql_cache_short",
317 "get_email_key_%s" % email))
317 "get_email_key_%s" % email))
318
318
319 ret = q.scalar()
319 ret = q.scalar()
320 if ret is None:
320 if ret is None:
321 q = UserEmailMap.query()
321 q = UserEmailMap.query()
322 # try fetching in alternate email map
322 # try fetching in alternate email map
323 if case_insensitive:
323 if case_insensitive:
324 q = q.filter(UserEmailMap.email.ilike(email))
324 q = q.filter(UserEmailMap.email.ilike(email))
325 else:
325 else:
326 q = q.filter(UserEmailMap.email == email)
326 q = q.filter(UserEmailMap.email == email)
327 q = q.options(joinedload(UserEmailMap.user))
327 q = q.options(joinedload(UserEmailMap.user))
328 if cache:
328 if cache:
329 q = q.options(FromCache("sql_cache_short",
329 q = q.options(FromCache("sql_cache_short",
330 "get_email_map_key_%s" % email))
330 "get_email_map_key_%s" % email))
331 ret = getattr(q.scalar(), 'user', None)
331 ret = getattr(q.scalar(), 'user', None)
332
332
333 return ret
333 return ret
334
334
335
335
336 class UserEmailMap(Base, BaseModel):
336 class UserEmailMap(Base, BaseModel):
337 __tablename__ = 'user_email_map'
337 __tablename__ = 'user_email_map'
338 __table_args__ = (
338 __table_args__ = (
339 Index('uem_email_idx', 'email'),
339 Index('uem_email_idx', 'email'),
340 UniqueConstraint('email'),
340 UniqueConstraint('email'),
341 {'extend_existing': True, 'mysql_engine': 'InnoDB',
341 {'extend_existing': True, 'mysql_engine': 'InnoDB',
342 'mysql_charset': 'utf8'}
342 'mysql_charset': 'utf8'}
343 )
343 )
344 __mapper_args__ = {}
344 __mapper_args__ = {}
345
345
346 email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
346 email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
347 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
347 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
348 _email = Column("email", String(255), nullable=True, unique=False, default=None)
348 _email = Column("email", String(255), nullable=True, unique=False, default=None)
349 user = relationship('User', lazy='joined')
349 user = relationship('User', lazy='joined')
350
350
351 @validates('_email')
351 @validates('_email')
352 def validate_email(self, key, email):
352 def validate_email(self, key, email):
353 # check if this email is not main one
353 # check if this email is not main one
354 main_email = Session().query(User).filter(User.email == email).scalar()
354 main_email = Session().query(User).filter(User.email == email).scalar()
355 if main_email is not None:
355 if main_email is not None:
356 raise AttributeError('email %s is present is user table' % email)
356 raise AttributeError('email %s is present is user table' % email)
357 return email
357 return email
358
358
359 @hybrid_property
359 @hybrid_property
360 def email(self):
360 def email(self):
361 return self._email
361 return self._email
362
362
363 @email.setter
363 @email.setter
364 def email(self, val):
364 def email(self, val):
365 self._email = val.lower() if val else None
365 self._email = val.lower() if val else None
366
366
367
367
368 class UserLog(Base, BaseModel):
368 class UserLog(Base, BaseModel):
369 __tablename__ = 'user_logs'
369 __tablename__ = 'user_logs'
370 __table_args__ = (
370 __table_args__ = (
371 {'extend_existing': True, 'mysql_engine': 'InnoDB',
371 {'extend_existing': True, 'mysql_engine': 'InnoDB',
372 'mysql_charset': 'utf8'},
372 'mysql_charset': 'utf8'},
373 )
373 )
374 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
374 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
375 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
375 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
376 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
376 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
377 repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None)
377 repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None)
378 user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None)
378 user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None)
379 action = Column("action", String(1200000), nullable=True, unique=None, default=None)
379 action = Column("action", String(1200000), nullable=True, unique=None, default=None)
380 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
380 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
381
381
382
382
383 user = relationship('User')
383 user = relationship('User')
384 repository = relationship('Repository', cascade='')
384 repository = relationship('Repository', cascade='')
385
385
386
386
387 class UserGroup(Base, BaseModel):
387 class UserGroup(Base, BaseModel):
388 __tablename__ = 'users_groups'
388 __tablename__ = 'users_groups'
389 __table_args__ = (
389 __table_args__ = (
390 {'extend_existing': True, 'mysql_engine': 'InnoDB',
390 {'extend_existing': True, 'mysql_engine': 'InnoDB',
391 'mysql_charset': 'utf8'},
391 'mysql_charset': 'utf8'},
392 )
392 )
393
393
394 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
394 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
395 users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None)
395 users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None)
396 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
396 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
397 inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
397 inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
398
398
399 members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
399 members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
400 users_group_to_perm = relationship('UserGroupToPerm', cascade='all')
400 users_group_to_perm = relationship('UserGroupToPerm', cascade='all')
401 users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
401 users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
402
402
403 def __unicode__(self):
403 def __unicode__(self):
404 return u'<userGroup(%s)>' % (self.users_group_name)
404 return u'<userGroup(%s)>' % (self.users_group_name)
405
405
406 @classmethod
406 @classmethod
407 def get_by_group_name(cls, group_name, cache=False,
407 def get_by_group_name(cls, group_name, cache=False,
408 case_insensitive=False):
408 case_insensitive=False):
409 if case_insensitive:
409 if case_insensitive:
410 q = cls.query().filter(cls.users_group_name.ilike(group_name))
410 q = cls.query().filter(cls.users_group_name.ilike(group_name))
411 else:
411 else:
412 q = cls.query().filter(cls.users_group_name == group_name)
412 q = cls.query().filter(cls.users_group_name == group_name)
413 if cache:
413 if cache:
414 q = q.options(FromCache(
414 q = q.options(FromCache(
415 "sql_cache_short",
415 "sql_cache_short",
416 "get_user_%s" % _hash_key(group_name)
416 "get_user_%s" % _hash_key(group_name)
417 )
417 )
418 )
418 )
419 return q.scalar()
419 return q.scalar()
420
420
421 @classmethod
421 @classmethod
422 def get(cls, users_group_id, cache=False):
422 def get(cls, users_group_id, cache=False):
423 user_group = cls.query()
423 user_group = cls.query()
424 if cache:
424 if cache:
425 user_group = user_group.options(FromCache("sql_cache_short",
425 user_group = user_group.options(FromCache("sql_cache_short",
426 "get_users_group_%s" % users_group_id))
426 "get_users_group_%s" % users_group_id))
427 return user_group.get(users_group_id)
427 return user_group.get(users_group_id)
428
428
429
429
430 class UserGroupMember(Base, BaseModel):
430 class UserGroupMember(Base, BaseModel):
431 __tablename__ = 'users_groups_members'
431 __tablename__ = 'users_groups_members'
432 __table_args__ = (
432 __table_args__ = (
433 {'extend_existing': True, 'mysql_engine': 'InnoDB',
433 {'extend_existing': True, 'mysql_engine': 'InnoDB',
434 'mysql_charset': 'utf8'},
434 'mysql_charset': 'utf8'},
435 )
435 )
436
436
437 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
437 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
438 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
438 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
439 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
439 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
440
440
441 user = relationship('User', lazy='joined')
441 user = relationship('User', lazy='joined')
442 users_group = relationship('UserGroup')
442 users_group = relationship('UserGroup')
443
443
444 def __init__(self, gr_id='', u_id=''):
444 def __init__(self, gr_id='', u_id=''):
445 self.users_group_id = gr_id
445 self.users_group_id = gr_id
446 self.user_id = u_id
446 self.user_id = u_id
447
447
448
448
449 class Repository(Base, BaseModel):
449 class Repository(Base, BaseModel):
450 __tablename__ = 'repositories'
450 __tablename__ = 'repositories'
451 __table_args__ = (
451 __table_args__ = (
452 UniqueConstraint('repo_name'),
452 UniqueConstraint('repo_name'),
453 Index('r_repo_name_idx', 'repo_name'),
453 Index('r_repo_name_idx', 'repo_name'),
454 {'extend_existing': True, 'mysql_engine': 'InnoDB',
454 {'extend_existing': True, 'mysql_engine': 'InnoDB',
455 'mysql_charset': 'utf8'},
455 'mysql_charset': 'utf8'},
456 )
456 )
457
457
458 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
458 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
459 repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None)
459 repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None)
460 clone_uri = Column("clone_uri", String(255), nullable=True, unique=False, default=None)
460 clone_uri = Column("clone_uri", String(255), nullable=True, unique=False, default=None)
461 repo_type = Column("repo_type", String(255), nullable=False, unique=False, default=None)
461 repo_type = Column("repo_type", String(255), nullable=False, unique=False, default=None)
462 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
462 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
463 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
463 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
464 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
464 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
465 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
465 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
466 description = Column("description", String(10000), nullable=True, unique=None, default=None)
466 description = Column("description", String(10000), nullable=True, unique=None, default=None)
467 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
467 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
468 updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
468 updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
469 landing_rev = Column("landing_revision", String(255), nullable=False, unique=False, default=None)
469 landing_rev = Column("landing_revision", String(255), nullable=False, unique=False, default=None)
470 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
470 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
471 _locked = Column("locked", String(255), nullable=True, unique=False, default=None)
471 _locked = Column("locked", String(255), nullable=True, unique=False, default=None)
472
472
473 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
473 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
474 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
474 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
475
475
476 user = relationship('User')
476 user = relationship('User')
477 fork = relationship('Repository', remote_side=repo_id)
477 fork = relationship('Repository', remote_side=repo_id)
478 group = relationship('RepoGroup')
478 group = relationship('RepoGroup')
479 repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
479 repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
480 users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
480 users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
481 stats = relationship('Statistics', cascade='all', uselist=False)
481 stats = relationship('Statistics', cascade='all', uselist=False)
482
482
483 followers = relationship('UserFollowing',
483 followers = relationship('UserFollowing',
484 primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id',
484 primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id',
485 cascade='all')
485 cascade='all')
486
486
487 logs = relationship('UserLog')
487 logs = relationship('UserLog')
488 comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan")
488 comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan")
489
489
490 pull_requests_org = relationship('PullRequest',
490 pull_requests_org = relationship('PullRequest',
491 primaryjoin='PullRequest.org_repo_id==Repository.repo_id',
491 primaryjoin='PullRequest.org_repo_id==Repository.repo_id',
492 cascade="all, delete, delete-orphan")
492 cascade="all, delete, delete-orphan")
493
493
494 pull_requests_other = relationship('PullRequest',
494 pull_requests_other = relationship('PullRequest',
495 primaryjoin='PullRequest.other_repo_id==Repository.repo_id',
495 primaryjoin='PullRequest.other_repo_id==Repository.repo_id',
496 cascade="all, delete, delete-orphan")
496 cascade="all, delete, delete-orphan")
497
497
498 def __unicode__(self):
498 def __unicode__(self):
499 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id,
499 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id,
500 self.repo_name)
500 self.repo_name)
501
501
502
502
503 @classmethod
503 @classmethod
504 def get_by_repo_name(cls, repo_name):
504 def get_by_repo_name(cls, repo_name):
505 q = Session().query(cls).filter(cls.repo_name == repo_name)
505 q = Session().query(cls).filter(cls.repo_name == repo_name)
506 q = q.options(joinedload(Repository.fork))\
506 q = q.options(joinedload(Repository.fork))\
507 .options(joinedload(Repository.user))\
507 .options(joinedload(Repository.user))\
508 .options(joinedload(Repository.group))
508 .options(joinedload(Repository.group))
509 return q.scalar()
509 return q.scalar()
510
510
511
511
512 class RepoGroup(Base, BaseModel):
512 class RepoGroup(Base, BaseModel):
513 __tablename__ = 'groups'
513 __tablename__ = 'groups'
514 __table_args__ = (
514 __table_args__ = (
515 UniqueConstraint('group_name', 'group_parent_id'),
515 UniqueConstraint('group_name', 'group_parent_id'),
516 CheckConstraint('group_id != group_parent_id'),
517 {'extend_existing': True, 'mysql_engine': 'InnoDB',
516 {'extend_existing': True, 'mysql_engine': 'InnoDB',
518 'mysql_charset': 'utf8'},
517 'mysql_charset': 'utf8'},
519 )
518 )
520 __mapper_args__ = {'order_by': 'group_name'}
519 __mapper_args__ = {'order_by': 'group_name'}
521
520
522 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
521 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
523 group_name = Column("group_name", String(255), nullable=False, unique=True, default=None)
522 group_name = Column("group_name", String(255), nullable=False, unique=True, default=None)
524 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
523 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
525 group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None)
524 group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None)
526 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
525 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
527
526
528 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
527 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
529 users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
528 users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
530 parent_group = relationship('RepoGroup', remote_side=group_id)
529 parent_group = relationship('RepoGroup', remote_side=group_id)
531
530
532 def __init__(self, group_name='', parent_group=None):
531 def __init__(self, group_name='', parent_group=None):
533 self.group_name = group_name
532 self.group_name = group_name
534 self.parent_group = parent_group
533 self.parent_group = parent_group
535
534
536 def __unicode__(self):
535 def __unicode__(self):
537 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
536 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
538 self.group_name)
537 self.group_name)
539
538
540 @classmethod
539 @classmethod
541 def url_sep(cls):
540 def url_sep(cls):
542 return URL_SEP
541 return URL_SEP
543
542
544 @classmethod
543 @classmethod
545 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
544 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
546 if case_insensitive:
545 if case_insensitive:
547 gr = cls.query()\
546 gr = cls.query()\
548 .filter(cls.group_name.ilike(group_name))
547 .filter(cls.group_name.ilike(group_name))
549 else:
548 else:
550 gr = cls.query()\
549 gr = cls.query()\
551 .filter(cls.group_name == group_name)
550 .filter(cls.group_name == group_name)
552 if cache:
551 if cache:
553 gr = gr.options(FromCache(
552 gr = gr.options(FromCache(
554 "sql_cache_short",
553 "sql_cache_short",
555 "get_group_%s" % _hash_key(group_name)
554 "get_group_%s" % _hash_key(group_name)
556 )
555 )
557 )
556 )
558 return gr.scalar()
557 return gr.scalar()
559
558
560
559
561 class Permission(Base, BaseModel):
560 class Permission(Base, BaseModel):
562 __tablename__ = 'permissions'
561 __tablename__ = 'permissions'
563 __table_args__ = (
562 __table_args__ = (
564 Index('p_perm_name_idx', 'permission_name'),
563 Index('p_perm_name_idx', 'permission_name'),
565 {'extend_existing': True, 'mysql_engine': 'InnoDB',
564 {'extend_existing': True, 'mysql_engine': 'InnoDB',
566 'mysql_charset': 'utf8'},
565 'mysql_charset': 'utf8'},
567 )
566 )
568 PERMS = [
567 PERMS = [
569 ('repository.none', _('Repository no access')),
568 ('repository.none', _('Repository no access')),
570 ('repository.read', _('Repository read access')),
569 ('repository.read', _('Repository read access')),
571 ('repository.write', _('Repository write access')),
570 ('repository.write', _('Repository write access')),
572 ('repository.admin', _('Repository admin access')),
571 ('repository.admin', _('Repository admin access')),
573
572
574 ('group.none', _('Repositories Group no access')),
573 ('group.none', _('Repositories Group no access')),
575 ('group.read', _('Repositories Group read access')),
574 ('group.read', _('Repositories Group read access')),
576 ('group.write', _('Repositories Group write access')),
575 ('group.write', _('Repositories Group write access')),
577 ('group.admin', _('Repositories Group admin access')),
576 ('group.admin', _('Repositories Group admin access')),
578
577
579 ('hg.admin', _('RhodeCode Administrator')),
578 ('hg.admin', _('RhodeCode Administrator')),
580 ('hg.create.none', _('Repository creation disabled')),
579 ('hg.create.none', _('Repository creation disabled')),
581 ('hg.create.repository', _('Repository creation enabled')),
580 ('hg.create.repository', _('Repository creation enabled')),
582 ('hg.fork.none', _('Repository forking disabled')),
581 ('hg.fork.none', _('Repository forking disabled')),
583 ('hg.fork.repository', _('Repository forking enabled')),
582 ('hg.fork.repository', _('Repository forking enabled')),
584 ('hg.register.none', _('Register disabled')),
583 ('hg.register.none', _('Register disabled')),
585 ('hg.register.manual_activate', _('Register new user with RhodeCode '
584 ('hg.register.manual_activate', _('Register new user with RhodeCode '
586 'with manual activation')),
585 'with manual activation')),
587
586
588 ('hg.register.auto_activate', _('Register new user with RhodeCode '
587 ('hg.register.auto_activate', _('Register new user with RhodeCode '
589 'with auto activation')),
588 'with auto activation')),
590 ]
589 ]
591
590
592 # defines which permissions are more important higher the more important
591 # defines which permissions are more important higher the more important
593 PERM_WEIGHTS = {
592 PERM_WEIGHTS = {
594 'repository.none': 0,
593 'repository.none': 0,
595 'repository.read': 1,
594 'repository.read': 1,
596 'repository.write': 3,
595 'repository.write': 3,
597 'repository.admin': 4,
596 'repository.admin': 4,
598
597
599 'group.none': 0,
598 'group.none': 0,
600 'group.read': 1,
599 'group.read': 1,
601 'group.write': 3,
600 'group.write': 3,
602 'group.admin': 4,
601 'group.admin': 4,
603
602
604 'hg.fork.none': 0,
603 'hg.fork.none': 0,
605 'hg.fork.repository': 1,
604 'hg.fork.repository': 1,
606 'hg.create.none': 0,
605 'hg.create.none': 0,
607 'hg.create.repository':1
606 'hg.create.repository':1
608 }
607 }
609
608
610 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
609 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
611 permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None)
610 permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None)
612 permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None)
611 permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None)
613
612
614 def __unicode__(self):
613 def __unicode__(self):
615 return u"<%s('%s:%s')>" % (
614 return u"<%s('%s:%s')>" % (
616 self.__class__.__name__, self.permission_id, self.permission_name
615 self.__class__.__name__, self.permission_id, self.permission_name
617 )
616 )
618
617
619 @classmethod
618 @classmethod
620 def get_by_key(cls, key):
619 def get_by_key(cls, key):
621 return cls.query().filter(cls.permission_name == key).scalar()
620 return cls.query().filter(cls.permission_name == key).scalar()
622
621
623
622
624 class UserRepoToPerm(Base, BaseModel):
623 class UserRepoToPerm(Base, BaseModel):
625 __tablename__ = 'repo_to_perm'
624 __tablename__ = 'repo_to_perm'
626 __table_args__ = (
625 __table_args__ = (
627 UniqueConstraint('user_id', 'repository_id', 'permission_id'),
626 UniqueConstraint('user_id', 'repository_id', 'permission_id'),
628 {'extend_existing': True, 'mysql_engine': 'InnoDB',
627 {'extend_existing': True, 'mysql_engine': 'InnoDB',
629 'mysql_charset': 'utf8'}
628 'mysql_charset': 'utf8'}
630 )
629 )
631 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
630 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
632 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
631 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
633 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
632 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
634 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
633 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
635
634
636 user = relationship('User')
635 user = relationship('User')
637 repository = relationship('Repository')
636 repository = relationship('Repository')
638 permission = relationship('Permission')
637 permission = relationship('Permission')
639
638
640 def __unicode__(self):
639 def __unicode__(self):
641 return u'<user:%s => %s >' % (self.user, self.repository)
640 return u'<user:%s => %s >' % (self.user, self.repository)
642
641
643
642
644 class UserToPerm(Base, BaseModel):
643 class UserToPerm(Base, BaseModel):
645 __tablename__ = 'user_to_perm'
644 __tablename__ = 'user_to_perm'
646 __table_args__ = (
645 __table_args__ = (
647 UniqueConstraint('user_id', 'permission_id'),
646 UniqueConstraint('user_id', 'permission_id'),
648 {'extend_existing': True, 'mysql_engine': 'InnoDB',
647 {'extend_existing': True, 'mysql_engine': 'InnoDB',
649 'mysql_charset': 'utf8'}
648 'mysql_charset': 'utf8'}
650 )
649 )
651 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
650 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
652 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
651 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
653 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
652 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
654
653
655 user = relationship('User')
654 user = relationship('User')
656 permission = relationship('Permission', lazy='joined')
655 permission = relationship('Permission', lazy='joined')
657
656
658
657
659 class UserGroupRepoToPerm(Base, BaseModel):
658 class UserGroupRepoToPerm(Base, BaseModel):
660 __tablename__ = 'users_group_repo_to_perm'
659 __tablename__ = 'users_group_repo_to_perm'
661 __table_args__ = (
660 __table_args__ = (
662 UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
661 UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
663 {'extend_existing': True, 'mysql_engine': 'InnoDB',
662 {'extend_existing': True, 'mysql_engine': 'InnoDB',
664 'mysql_charset': 'utf8'}
663 'mysql_charset': 'utf8'}
665 )
664 )
666 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
665 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
667 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
666 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
668 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
667 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
669 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
668 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
670
669
671 users_group = relationship('UserGroup')
670 users_group = relationship('UserGroup')
672 permission = relationship('Permission')
671 permission = relationship('Permission')
673 repository = relationship('Repository')
672 repository = relationship('Repository')
674
673
675 def __unicode__(self):
674 def __unicode__(self):
676 return u'<userGroup:%s => %s >' % (self.users_group, self.repository)
675 return u'<userGroup:%s => %s >' % (self.users_group, self.repository)
677
676
678
677
679 class UserGroupToPerm(Base, BaseModel):
678 class UserGroupToPerm(Base, BaseModel):
680 __tablename__ = 'users_group_to_perm'
679 __tablename__ = 'users_group_to_perm'
681 __table_args__ = (
680 __table_args__ = (
682 UniqueConstraint('users_group_id', 'permission_id',),
681 UniqueConstraint('users_group_id', 'permission_id',),
683 {'extend_existing': True, 'mysql_engine': 'InnoDB',
682 {'extend_existing': True, 'mysql_engine': 'InnoDB',
684 'mysql_charset': 'utf8'}
683 'mysql_charset': 'utf8'}
685 )
684 )
686 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
685 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
687 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
686 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
688 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
687 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
689
688
690 users_group = relationship('UserGroup')
689 users_group = relationship('UserGroup')
691 permission = relationship('Permission')
690 permission = relationship('Permission')
692
691
693
692
694 class UserRepoGroupToPerm(Base, BaseModel):
693 class UserRepoGroupToPerm(Base, BaseModel):
695 __tablename__ = 'user_repo_group_to_perm'
694 __tablename__ = 'user_repo_group_to_perm'
696 __table_args__ = (
695 __table_args__ = (
697 UniqueConstraint('user_id', 'group_id', 'permission_id'),
696 UniqueConstraint('user_id', 'group_id', 'permission_id'),
698 {'extend_existing': True, 'mysql_engine': 'InnoDB',
697 {'extend_existing': True, 'mysql_engine': 'InnoDB',
699 'mysql_charset': 'utf8'}
698 'mysql_charset': 'utf8'}
700 )
699 )
701
700
702 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
701 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
703 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
702 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
704 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
703 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
705 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
704 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
706
705
707 user = relationship('User')
706 user = relationship('User')
708 group = relationship('RepoGroup')
707 group = relationship('RepoGroup')
709 permission = relationship('Permission')
708 permission = relationship('Permission')
710
709
711
710
712 class UserGroupRepoGroupToPerm(Base, BaseModel):
711 class UserGroupRepoGroupToPerm(Base, BaseModel):
713 __tablename__ = 'users_group_repo_group_to_perm'
712 __tablename__ = 'users_group_repo_group_to_perm'
714 __table_args__ = (
713 __table_args__ = (
715 UniqueConstraint('users_group_id', 'group_id'),
714 UniqueConstraint('users_group_id', 'group_id'),
716 {'extend_existing': True, 'mysql_engine': 'InnoDB',
715 {'extend_existing': True, 'mysql_engine': 'InnoDB',
717 'mysql_charset': 'utf8'}
716 'mysql_charset': 'utf8'}
718 )
717 )
719
718
720 users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
719 users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
721 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
720 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
722 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
721 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
723 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
722 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
724
723
725 users_group = relationship('UserGroup')
724 users_group = relationship('UserGroup')
726 permission = relationship('Permission')
725 permission = relationship('Permission')
727 group = relationship('RepoGroup')
726 group = relationship('RepoGroup')
728
727
729
728
730 class Statistics(Base, BaseModel):
729 class Statistics(Base, BaseModel):
731 __tablename__ = 'statistics'
730 __tablename__ = 'statistics'
732 __table_args__ = (
731 __table_args__ = (
733 UniqueConstraint('repository_id'),
732 UniqueConstraint('repository_id'),
734 {'extend_existing': True, 'mysql_engine': 'InnoDB',
733 {'extend_existing': True, 'mysql_engine': 'InnoDB',
735 'mysql_charset': 'utf8'}
734 'mysql_charset': 'utf8'}
736 )
735 )
737 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
736 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
738 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
737 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
739 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
738 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
740 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
739 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
741 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
740 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
742 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
741 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
743
742
744 repository = relationship('Repository', single_parent=True)
743 repository = relationship('Repository', single_parent=True)
745
744
746
745
747 class UserFollowing(Base, BaseModel):
746 class UserFollowing(Base, BaseModel):
748 __tablename__ = 'user_followings'
747 __tablename__ = 'user_followings'
749 __table_args__ = (
748 __table_args__ = (
750 UniqueConstraint('user_id', 'follows_repository_id'),
749 UniqueConstraint('user_id', 'follows_repository_id'),
751 UniqueConstraint('user_id', 'follows_user_id'),
750 UniqueConstraint('user_id', 'follows_user_id'),
752 {'extend_existing': True, 'mysql_engine': 'InnoDB',
751 {'extend_existing': True, 'mysql_engine': 'InnoDB',
753 'mysql_charset': 'utf8'}
752 'mysql_charset': 'utf8'}
754 )
753 )
755
754
756 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
755 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
757 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
756 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
758 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
757 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
759 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
758 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
760 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
759 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
761
760
762 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
761 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
763
762
764 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
763 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
765 follows_repository = relationship('Repository', order_by='Repository.repo_name')
764 follows_repository = relationship('Repository', order_by='Repository.repo_name')
766
765
767
766
768 class CacheInvalidation(Base, BaseModel):
767 class CacheInvalidation(Base, BaseModel):
769 __tablename__ = 'cache_invalidation'
768 __tablename__ = 'cache_invalidation'
770 __table_args__ = (
769 __table_args__ = (
771 UniqueConstraint('cache_key'),
770 UniqueConstraint('cache_key'),
772 Index('key_idx', 'cache_key'),
771 Index('key_idx', 'cache_key'),
773 {'extend_existing': True, 'mysql_engine': 'InnoDB',
772 {'extend_existing': True, 'mysql_engine': 'InnoDB',
774 'mysql_charset': 'utf8'},
773 'mysql_charset': 'utf8'},
775 )
774 )
776 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
775 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
777 cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None)
776 cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None)
778 cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None)
777 cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None)
779 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
778 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
780
779
781 def __init__(self, cache_key, cache_args=''):
780 def __init__(self, cache_key, cache_args=''):
782 self.cache_key = cache_key
781 self.cache_key = cache_key
783 self.cache_args = cache_args
782 self.cache_args = cache_args
784 self.cache_active = False
783 self.cache_active = False
785
784
786
785
787 class ChangesetComment(Base, BaseModel):
786 class ChangesetComment(Base, BaseModel):
788 __tablename__ = 'changeset_comments'
787 __tablename__ = 'changeset_comments'
789 __table_args__ = (
788 __table_args__ = (
790 Index('cc_revision_idx', 'revision'),
789 Index('cc_revision_idx', 'revision'),
791 {'extend_existing': True, 'mysql_engine': 'InnoDB',
790 {'extend_existing': True, 'mysql_engine': 'InnoDB',
792 'mysql_charset': 'utf8'},
791 'mysql_charset': 'utf8'},
793 )
792 )
794 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
793 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
795 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
794 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
796 revision = Column('revision', String(40), nullable=True)
795 revision = Column('revision', String(40), nullable=True)
797 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
796 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
798 line_no = Column('line_no', Unicode(10), nullable=True)
797 line_no = Column('line_no', Unicode(10), nullable=True)
799 hl_lines = Column('hl_lines', Unicode(512), nullable=True)
798 hl_lines = Column('hl_lines', Unicode(512), nullable=True)
800 f_path = Column('f_path', Unicode(1000), nullable=True)
799 f_path = Column('f_path', Unicode(1000), nullable=True)
801 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
800 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
802 text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False)
801 text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False)
803 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
802 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
804 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
803 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
805
804
806 author = relationship('User', lazy='joined')
805 author = relationship('User', lazy='joined')
807 repo = relationship('Repository')
806 repo = relationship('Repository')
808 status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan")
807 status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan")
809 pull_request = relationship('PullRequest', lazy='joined')
808 pull_request = relationship('PullRequest', lazy='joined')
810
809
811 @classmethod
810 @classmethod
812 def get_users(cls, revision=None, pull_request_id=None):
811 def get_users(cls, revision=None, pull_request_id=None):
813 """
812 """
814 Returns user associated with this ChangesetComment. ie those
813 Returns user associated with this ChangesetComment. ie those
815 who actually commented
814 who actually commented
816
815
817 :param cls:
816 :param cls:
818 :param revision:
817 :param revision:
819 """
818 """
820 q = Session().query(User)\
819 q = Session().query(User)\
821 .join(ChangesetComment.author)
820 .join(ChangesetComment.author)
822 if revision:
821 if revision:
823 q = q.filter(cls.revision == revision)
822 q = q.filter(cls.revision == revision)
824 elif pull_request_id:
823 elif pull_request_id:
825 q = q.filter(cls.pull_request_id == pull_request_id)
824 q = q.filter(cls.pull_request_id == pull_request_id)
826 return q.all()
825 return q.all()
827
826
828
827
829 class ChangesetStatus(Base, BaseModel):
828 class ChangesetStatus(Base, BaseModel):
830 __tablename__ = 'changeset_statuses'
829 __tablename__ = 'changeset_statuses'
831 __table_args__ = (
830 __table_args__ = (
832 Index('cs_revision_idx', 'revision'),
831 Index('cs_revision_idx', 'revision'),
833 Index('cs_version_idx', 'version'),
832 Index('cs_version_idx', 'version'),
834 UniqueConstraint('repo_id', 'revision', 'version'),
833 UniqueConstraint('repo_id', 'revision', 'version'),
835 {'extend_existing': True, 'mysql_engine': 'InnoDB',
834 {'extend_existing': True, 'mysql_engine': 'InnoDB',
836 'mysql_charset': 'utf8'}
835 'mysql_charset': 'utf8'}
837 )
836 )
838 STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed'
837 STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed'
839 STATUS_APPROVED = 'approved'
838 STATUS_APPROVED = 'approved'
840 STATUS_REJECTED = 'rejected'
839 STATUS_REJECTED = 'rejected'
841 STATUS_UNDER_REVIEW = 'under_review'
840 STATUS_UNDER_REVIEW = 'under_review'
842
841
843 STATUSES = [
842 STATUSES = [
844 (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default
843 (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default
845 (STATUS_APPROVED, _("Approved")),
844 (STATUS_APPROVED, _("Approved")),
846 (STATUS_REJECTED, _("Rejected")),
845 (STATUS_REJECTED, _("Rejected")),
847 (STATUS_UNDER_REVIEW, _("Under Review")),
846 (STATUS_UNDER_REVIEW, _("Under Review")),
848 ]
847 ]
849
848
850 changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True)
849 changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True)
851 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
850 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
852 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
851 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
853 revision = Column('revision', String(40), nullable=False)
852 revision = Column('revision', String(40), nullable=False)
854 status = Column('status', String(128), nullable=False, default=DEFAULT)
853 status = Column('status', String(128), nullable=False, default=DEFAULT)
855 changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id'))
854 changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id'))
856 modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
855 modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
857 version = Column('version', Integer(), nullable=False, default=0)
856 version = Column('version', Integer(), nullable=False, default=0)
858 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
857 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
859
858
860 author = relationship('User', lazy='joined')
859 author = relationship('User', lazy='joined')
861 repo = relationship('Repository')
860 repo = relationship('Repository')
862 comment = relationship('ChangesetComment', lazy='joined')
861 comment = relationship('ChangesetComment', lazy='joined')
863 pull_request = relationship('PullRequest', lazy='joined')
862 pull_request = relationship('PullRequest', lazy='joined')
864
863
865
864
866
865
867 class PullRequest(Base, BaseModel):
866 class PullRequest(Base, BaseModel):
868 __tablename__ = 'pull_requests'
867 __tablename__ = 'pull_requests'
869 __table_args__ = (
868 __table_args__ = (
870 {'extend_existing': True, 'mysql_engine': 'InnoDB',
869 {'extend_existing': True, 'mysql_engine': 'InnoDB',
871 'mysql_charset': 'utf8'},
870 'mysql_charset': 'utf8'},
872 )
871 )
873
872
874 STATUS_NEW = u'new'
873 STATUS_NEW = u'new'
875 STATUS_OPEN = u'open'
874 STATUS_OPEN = u'open'
876 STATUS_CLOSED = u'closed'
875 STATUS_CLOSED = u'closed'
877
876
878 pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True)
877 pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True)
879 title = Column('title', Unicode(256), nullable=True)
878 title = Column('title', Unicode(256), nullable=True)
880 description = Column('description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), nullable=True)
879 description = Column('description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), nullable=True)
881 status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW)
880 status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW)
882 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
881 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
883 updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
882 updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
884 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
883 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
885 _revisions = Column('revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql'))
884 _revisions = Column('revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql'))
886 org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
885 org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
887 org_ref = Column('org_ref', Unicode(256), nullable=False)
886 org_ref = Column('org_ref', Unicode(256), nullable=False)
888 other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
887 other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
889 other_ref = Column('other_ref', Unicode(256), nullable=False)
888 other_ref = Column('other_ref', Unicode(256), nullable=False)
890
889
891 author = relationship('User', lazy='joined')
890 author = relationship('User', lazy='joined')
892 reviewers = relationship('PullRequestReviewers',
891 reviewers = relationship('PullRequestReviewers',
893 cascade="all, delete, delete-orphan")
892 cascade="all, delete, delete-orphan")
894 org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id')
893 org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id')
895 other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id')
894 other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id')
896 statuses = relationship('ChangesetStatus')
895 statuses = relationship('ChangesetStatus')
897 comments = relationship('ChangesetComment',
896 comments = relationship('ChangesetComment',
898 cascade="all, delete, delete-orphan")
897 cascade="all, delete, delete-orphan")
899
898
900
899
901 class PullRequestReviewers(Base, BaseModel):
900 class PullRequestReviewers(Base, BaseModel):
902 __tablename__ = 'pull_request_reviewers'
901 __tablename__ = 'pull_request_reviewers'
903 __table_args__ = (
902 __table_args__ = (
904 {'extend_existing': True, 'mysql_engine': 'InnoDB',
903 {'extend_existing': True, 'mysql_engine': 'InnoDB',
905 'mysql_charset': 'utf8'},
904 'mysql_charset': 'utf8'},
906 )
905 )
907
906
908 def __init__(self, user=None, pull_request=None):
907 def __init__(self, user=None, pull_request=None):
909 self.user = user
908 self.user = user
910 self.pull_request = pull_request
909 self.pull_request = pull_request
911
910
912 pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True)
911 pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True)
913 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False)
912 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False)
914 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True)
913 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True)
915
914
916 user = relationship('User')
915 user = relationship('User')
917 pull_request = relationship('PullRequest')
916 pull_request = relationship('PullRequest')
918
917
919
918
920 class Notification(Base, BaseModel):
919 class Notification(Base, BaseModel):
921 __tablename__ = 'notifications'
920 __tablename__ = 'notifications'
922 __table_args__ = (
921 __table_args__ = (
923 Index('notification_type_idx', 'type'),
922 Index('notification_type_idx', 'type'),
924 {'extend_existing': True, 'mysql_engine': 'InnoDB',
923 {'extend_existing': True, 'mysql_engine': 'InnoDB',
925 'mysql_charset': 'utf8'},
924 'mysql_charset': 'utf8'},
926 )
925 )
927
926
928 TYPE_CHANGESET_COMMENT = u'cs_comment'
927 TYPE_CHANGESET_COMMENT = u'cs_comment'
929 TYPE_MESSAGE = u'message'
928 TYPE_MESSAGE = u'message'
930 TYPE_MENTION = u'mention'
929 TYPE_MENTION = u'mention'
931 TYPE_REGISTRATION = u'registration'
930 TYPE_REGISTRATION = u'registration'
932 TYPE_PULL_REQUEST = u'pull_request'
931 TYPE_PULL_REQUEST = u'pull_request'
933 TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment'
932 TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment'
934
933
935 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
934 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
936 subject = Column('subject', Unicode(512), nullable=True)
935 subject = Column('subject', Unicode(512), nullable=True)
937 body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True)
936 body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True)
938 created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
937 created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
939 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
938 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
940 type_ = Column('type', Unicode(256))
939 type_ = Column('type', Unicode(256))
941
940
942 created_by_user = relationship('User')
941 created_by_user = relationship('User')
943 notifications_to_users = relationship('UserNotification', lazy='joined',
942 notifications_to_users = relationship('UserNotification', lazy='joined',
944 cascade="all, delete, delete-orphan")
943 cascade="all, delete, delete-orphan")
945
944
946
945
947 class UserNotification(Base, BaseModel):
946 class UserNotification(Base, BaseModel):
948 __tablename__ = 'user_to_notification'
947 __tablename__ = 'user_to_notification'
949 __table_args__ = (
948 __table_args__ = (
950 UniqueConstraint('user_id', 'notification_id'),
949 UniqueConstraint('user_id', 'notification_id'),
951 {'extend_existing': True, 'mysql_engine': 'InnoDB',
950 {'extend_existing': True, 'mysql_engine': 'InnoDB',
952 'mysql_charset': 'utf8'}
951 'mysql_charset': 'utf8'}
953 )
952 )
954 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
953 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
955 notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
954 notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
956 read = Column('read', Boolean, default=False)
955 read = Column('read', Boolean, default=False)
957 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
956 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
958
957
959 user = relationship('User', lazy="joined")
958 user = relationship('User', lazy="joined")
960 notification = relationship('Notification', lazy="joined",
959 notification = relationship('Notification', lazy="joined",
961 order_by=lambda: Notification.created_on.desc(),)
960 order_by=lambda: Notification.created_on.desc(),)
962
961
963
962
964 class DbMigrateVersion(Base, BaseModel):
963 class DbMigrateVersion(Base, BaseModel):
965 __tablename__ = 'db_migrate_version'
964 __tablename__ = 'db_migrate_version'
966 __table_args__ = (
965 __table_args__ = (
967 {'extend_existing': True, 'mysql_engine': 'InnoDB',
966 {'extend_existing': True, 'mysql_engine': 'InnoDB',
968 'mysql_charset': 'utf8'},
967 'mysql_charset': 'utf8'},
969 )
968 )
970 repository_id = Column('repository_id', String(250), primary_key=True)
969 repository_id = Column('repository_id', String(250), primary_key=True)
971 repository_path = Column('repository_path', Text)
970 repository_path = Column('repository_path', Text)
972 version = Column('version', Integer)
971 version = Column('version', Integer)
@@ -1,993 +1,992 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2019 RhodeCode GmbH
3 # Copyright (C) 2010-2019 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21
21
22 import os
22 import os
23 import time
23 import time
24 import logging
24 import logging
25 import datetime
25 import datetime
26 import traceback
26 import traceback
27 import hashlib
27 import hashlib
28 import collections
28 import collections
29
29
30 from sqlalchemy import *
30 from sqlalchemy import *
31 from sqlalchemy.ext.hybrid import hybrid_property
31 from sqlalchemy.ext.hybrid import hybrid_property
32 from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
32 from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
33 from sqlalchemy.exc import DatabaseError
33 from sqlalchemy.exc import DatabaseError
34 from beaker.cache import cache_region, region_invalidate
34 from beaker.cache import cache_region, region_invalidate
35 from webob.exc import HTTPNotFound
35 from webob.exc import HTTPNotFound
36
36
37 from rhodecode.translation import _
37 from rhodecode.translation import _
38
38
39 from rhodecode.lib.vcs import get_backend
39 from rhodecode.lib.vcs import get_backend
40 from rhodecode.lib.vcs.utils.helpers import get_scm
40 from rhodecode.lib.vcs.utils.helpers import get_scm
41 from rhodecode.lib.vcs.exceptions import VCSError
41 from rhodecode.lib.vcs.exceptions import VCSError
42 from zope.cachedescriptors.property import Lazy as LazyProperty
42 from zope.cachedescriptors.property import Lazy as LazyProperty
43
43
44 from rhodecode.lib.utils2 import str2bool, safe_str, get_commit_safe, \
44 from rhodecode.lib.utils2 import str2bool, safe_str, get_commit_safe, \
45 safe_unicode, remove_suffix, remove_prefix
45 safe_unicode, remove_suffix, remove_prefix
46 from rhodecode.lib.ext_json import json
46 from rhodecode.lib.ext_json import json
47 from rhodecode.lib.caching_query import FromCache
47 from rhodecode.lib.caching_query import FromCache
48
48
49 from rhodecode.model.meta import Base, Session
49 from rhodecode.model.meta import Base, Session
50
50
51 URL_SEP = '/'
51 URL_SEP = '/'
52 log = logging.getLogger(__name__)
52 log = logging.getLogger(__name__)
53
53
54 #==============================================================================
54 #==============================================================================
55 # BASE CLASSES
55 # BASE CLASSES
56 #==============================================================================
56 #==============================================================================
57
57
58 _hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest()
58 _hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest()
59
59
60
60
61 class BaseModel(object):
61 class BaseModel(object):
62 """
62 """
63 Base Model for all classes
63 Base Model for all classes
64 """
64 """
65
65
66 @classmethod
66 @classmethod
67 def _get_keys(cls):
67 def _get_keys(cls):
68 """return column names for this model """
68 """return column names for this model """
69 return class_mapper(cls).c.keys()
69 return class_mapper(cls).c.keys()
70
70
71 def get_dict(self):
71 def get_dict(self):
72 """
72 """
73 return dict with keys and values corresponding
73 return dict with keys and values corresponding
74 to this model data """
74 to this model data """
75
75
76 d = {}
76 d = {}
77 for k in self._get_keys():
77 for k in self._get_keys():
78 d[k] = getattr(self, k)
78 d[k] = getattr(self, k)
79
79
80 # also use __json__() if present to get additional fields
80 # also use __json__() if present to get additional fields
81 _json_attr = getattr(self, '__json__', None)
81 _json_attr = getattr(self, '__json__', None)
82 if _json_attr:
82 if _json_attr:
83 # update with attributes from __json__
83 # update with attributes from __json__
84 if callable(_json_attr):
84 if callable(_json_attr):
85 _json_attr = _json_attr()
85 _json_attr = _json_attr()
86 for k, val in _json_attr.iteritems():
86 for k, val in _json_attr.iteritems():
87 d[k] = val
87 d[k] = val
88 return d
88 return d
89
89
90 def get_appstruct(self):
90 def get_appstruct(self):
91 """return list with keys and values tupples corresponding
91 """return list with keys and values tupples corresponding
92 to this model data """
92 to this model data """
93
93
94 l = []
94 l = []
95 for k in self._get_keys():
95 for k in self._get_keys():
96 l.append((k, getattr(self, k),))
96 l.append((k, getattr(self, k),))
97 return l
97 return l
98
98
99 def populate_obj(self, populate_dict):
99 def populate_obj(self, populate_dict):
100 """populate model with data from given populate_dict"""
100 """populate model with data from given populate_dict"""
101
101
102 for k in self._get_keys():
102 for k in self._get_keys():
103 if k in populate_dict:
103 if k in populate_dict:
104 setattr(self, k, populate_dict[k])
104 setattr(self, k, populate_dict[k])
105
105
106 @classmethod
106 @classmethod
107 def query(cls):
107 def query(cls):
108 return Session().query(cls)
108 return Session().query(cls)
109
109
110 @classmethod
110 @classmethod
111 def get(cls, id_):
111 def get(cls, id_):
112 if id_:
112 if id_:
113 return cls.query().get(id_)
113 return cls.query().get(id_)
114
114
115 @classmethod
115 @classmethod
116 def get_or_404(cls, id_):
116 def get_or_404(cls, id_):
117 try:
117 try:
118 id_ = int(id_)
118 id_ = int(id_)
119 except (TypeError, ValueError):
119 except (TypeError, ValueError):
120 raise HTTPNotFound
120 raise HTTPNotFound
121
121
122 res = cls.query().get(id_)
122 res = cls.query().get(id_)
123 if not res:
123 if not res:
124 raise HTTPNotFound
124 raise HTTPNotFound
125 return res
125 return res
126
126
127 @classmethod
127 @classmethod
128 def getAll(cls):
128 def getAll(cls):
129 # deprecated and left for backward compatibility
129 # deprecated and left for backward compatibility
130 return cls.get_all()
130 return cls.get_all()
131
131
132 @classmethod
132 @classmethod
133 def get_all(cls):
133 def get_all(cls):
134 return cls.query().all()
134 return cls.query().all()
135
135
136 @classmethod
136 @classmethod
137 def delete(cls, id_):
137 def delete(cls, id_):
138 obj = cls.query().get(id_)
138 obj = cls.query().get(id_)
139 Session().delete(obj)
139 Session().delete(obj)
140
140
141 def __repr__(self):
141 def __repr__(self):
142 if hasattr(self, '__unicode__'):
142 if hasattr(self, '__unicode__'):
143 # python repr needs to return str
143 # python repr needs to return str
144 return safe_str(self.__unicode__())
144 return safe_str(self.__unicode__())
145 return '<DB:%s>' % (self.__class__.__name__)
145 return '<DB:%s>' % (self.__class__.__name__)
146
146
147
147
148 class RhodeCodeSetting(Base, BaseModel):
148 class RhodeCodeSetting(Base, BaseModel):
149 __tablename__ = 'rhodecode_settings'
149 __tablename__ = 'rhodecode_settings'
150 __table_args__ = (
150 __table_args__ = (
151 UniqueConstraint('app_settings_name'),
151 UniqueConstraint('app_settings_name'),
152 {'extend_existing': True, 'mysql_engine': 'InnoDB',
152 {'extend_existing': True, 'mysql_engine': 'InnoDB',
153 'mysql_charset': 'utf8'}
153 'mysql_charset': 'utf8'}
154 )
154 )
155 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
155 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
156 app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None)
156 app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None)
157 _app_settings_value = Column("app_settings_value", String(255), nullable=True, unique=None, default=None)
157 _app_settings_value = Column("app_settings_value", String(255), nullable=True, unique=None, default=None)
158
158
159 def __init__(self, k='', v=''):
159 def __init__(self, k='', v=''):
160 self.app_settings_name = k
160 self.app_settings_name = k
161 self.app_settings_value = v
161 self.app_settings_value = v
162
162
163 @validates('_app_settings_value')
163 @validates('_app_settings_value')
164 def validate_settings_value(self, key, val):
164 def validate_settings_value(self, key, val):
165 assert type(val) == unicode
165 assert type(val) == unicode
166 return val
166 return val
167
167
168 @hybrid_property
168 @hybrid_property
169 def app_settings_value(self):
169 def app_settings_value(self):
170 v = self._app_settings_value
170 v = self._app_settings_value
171 if self.app_settings_name in ["ldap_active",
171 if self.app_settings_name in ["ldap_active",
172 "default_repo_enable_statistics",
172 "default_repo_enable_statistics",
173 "default_repo_enable_locking",
173 "default_repo_enable_locking",
174 "default_repo_private",
174 "default_repo_private",
175 "default_repo_enable_downloads"]:
175 "default_repo_enable_downloads"]:
176 v = str2bool(v)
176 v = str2bool(v)
177 return v
177 return v
178
178
179 @app_settings_value.setter
179 @app_settings_value.setter
180 def app_settings_value(self, val):
180 def app_settings_value(self, val):
181 """
181 """
182 Setter that will always make sure we use unicode in app_settings_value
182 Setter that will always make sure we use unicode in app_settings_value
183
183
184 :param val:
184 :param val:
185 """
185 """
186 self._app_settings_value = safe_unicode(val)
186 self._app_settings_value = safe_unicode(val)
187
187
188 def __unicode__(self):
188 def __unicode__(self):
189 return u"<%s('%s:%s')>" % (
189 return u"<%s('%s:%s')>" % (
190 self.__class__.__name__,
190 self.__class__.__name__,
191 self.app_settings_name, self.app_settings_value
191 self.app_settings_name, self.app_settings_value
192 )
192 )
193
193
194
194
195 class RhodeCodeUi(Base, BaseModel):
195 class RhodeCodeUi(Base, BaseModel):
196 __tablename__ = 'rhodecode_ui'
196 __tablename__ = 'rhodecode_ui'
197 __table_args__ = (
197 __table_args__ = (
198 UniqueConstraint('ui_key'),
198 UniqueConstraint('ui_key'),
199 {'extend_existing': True, 'mysql_engine': 'InnoDB',
199 {'extend_existing': True, 'mysql_engine': 'InnoDB',
200 'mysql_charset': 'utf8'}
200 'mysql_charset': 'utf8'}
201 )
201 )
202
202
203 HOOK_REPO_SIZE = 'changegroup.repo_size'
203 HOOK_REPO_SIZE = 'changegroup.repo_size'
204 HOOK_PUSH = 'changegroup.push_logger'
204 HOOK_PUSH = 'changegroup.push_logger'
205 HOOK_PRE_PUSH = 'prechangegroup.pre_push'
205 HOOK_PRE_PUSH = 'prechangegroup.pre_push'
206 HOOK_PULL = 'outgoing.pull_logger'
206 HOOK_PULL = 'outgoing.pull_logger'
207 HOOK_PRE_PULL = 'preoutgoing.pre_pull'
207 HOOK_PRE_PULL = 'preoutgoing.pre_pull'
208
208
209 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
209 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
210 ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None)
210 ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None)
211 ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None)
211 ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None)
212 ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None)
212 ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None)
213 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
213 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
214
214
215
215
216
216
217 class User(Base, BaseModel):
217 class User(Base, BaseModel):
218 __tablename__ = 'users'
218 __tablename__ = 'users'
219 __table_args__ = (
219 __table_args__ = (
220 UniqueConstraint('username'), UniqueConstraint('email'),
220 UniqueConstraint('username'), UniqueConstraint('email'),
221 Index('u_username_idx', 'username'),
221 Index('u_username_idx', 'username'),
222 Index('u_email_idx', 'email'),
222 Index('u_email_idx', 'email'),
223 {'extend_existing': True, 'mysql_engine': 'InnoDB',
223 {'extend_existing': True, 'mysql_engine': 'InnoDB',
224 'mysql_charset': 'utf8'}
224 'mysql_charset': 'utf8'}
225 )
225 )
226 DEFAULT_USER = 'default'
226 DEFAULT_USER = 'default'
227 DEFAULT_PERMISSIONS = [
227 DEFAULT_PERMISSIONS = [
228 'hg.register.manual_activate', 'hg.create.repository',
228 'hg.register.manual_activate', 'hg.create.repository',
229 'hg.fork.repository', 'repository.read', 'group.read'
229 'hg.fork.repository', 'repository.read', 'group.read'
230 ]
230 ]
231 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
231 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
232 username = Column("username", String(255), nullable=True, unique=None, default=None)
232 username = Column("username", String(255), nullable=True, unique=None, default=None)
233 password = Column("password", String(255), nullable=True, unique=None, default=None)
233 password = Column("password", String(255), nullable=True, unique=None, default=None)
234 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
234 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
235 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
235 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
236 name = Column("firstname", String(255), nullable=True, unique=None, default=None)
236 name = Column("firstname", String(255), nullable=True, unique=None, default=None)
237 lastname = Column("lastname", String(255), nullable=True, unique=None, default=None)
237 lastname = Column("lastname", String(255), nullable=True, unique=None, default=None)
238 _email = Column("email", String(255), nullable=True, unique=None, default=None)
238 _email = Column("email", String(255), nullable=True, unique=None, default=None)
239 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
239 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
240 ldap_dn = Column("ldap_dn", String(255), nullable=True, unique=None, default=None)
240 ldap_dn = Column("ldap_dn", String(255), nullable=True, unique=None, default=None)
241 api_key = Column("api_key", String(255), nullable=True, unique=None, default=None)
241 api_key = Column("api_key", String(255), nullable=True, unique=None, default=None)
242 inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
242 inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
243
243
244 user_log = relationship('UserLog')
244 user_log = relationship('UserLog')
245 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
245 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
246
246
247 repositories = relationship('Repository')
247 repositories = relationship('Repository')
248 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
248 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
249 followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all')
249 followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all')
250
250
251 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
251 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
252 repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all')
252 repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all')
253
253
254 group_member = relationship('UserGroupMember', cascade='all')
254 group_member = relationship('UserGroupMember', cascade='all')
255
255
256 notifications = relationship('UserNotification', cascade='all')
256 notifications = relationship('UserNotification', cascade='all')
257 # notifications assigned to this user
257 # notifications assigned to this user
258 user_created_notifications = relationship('Notification', cascade='all')
258 user_created_notifications = relationship('Notification', cascade='all')
259 # comments created by this user
259 # comments created by this user
260 user_comments = relationship('ChangesetComment', cascade='all')
260 user_comments = relationship('ChangesetComment', cascade='all')
261 user_emails = relationship('UserEmailMap', cascade='all')
261 user_emails = relationship('UserEmailMap', cascade='all')
262
262
263 @hybrid_property
263 @hybrid_property
264 def email(self):
264 def email(self):
265 return self._email
265 return self._email
266
266
267 @email.setter
267 @email.setter
268 def email(self, val):
268 def email(self, val):
269 self._email = val.lower() if val else None
269 self._email = val.lower() if val else None
270
270
271 @property
271 @property
272 def firstname(self):
272 def firstname(self):
273 # alias for future
273 # alias for future
274 return self.name
274 return self.name
275
275
276 @property
276 @property
277 def username_and_name(self):
277 def username_and_name(self):
278 return '%s (%s %s)' % (self.username, self.firstname, self.lastname)
278 return '%s (%s %s)' % (self.username, self.firstname, self.lastname)
279
279
280 @property
280 @property
281 def full_name(self):
281 def full_name(self):
282 return '%s %s' % (self.firstname, self.lastname)
282 return '%s %s' % (self.firstname, self.lastname)
283
283
284 @property
284 @property
285 def full_contact(self):
285 def full_contact(self):
286 return '%s %s <%s>' % (self.firstname, self.lastname, self.email)
286 return '%s %s <%s>' % (self.firstname, self.lastname, self.email)
287
287
288 @property
288 @property
289 def short_contact(self):
289 def short_contact(self):
290 return '%s %s' % (self.firstname, self.lastname)
290 return '%s %s' % (self.firstname, self.lastname)
291
291
292 @property
292 @property
293 def is_admin(self):
293 def is_admin(self):
294 return self.admin
294 return self.admin
295
295
296 @classmethod
296 @classmethod
297 def get_by_username(cls, username, case_insensitive=False, cache=False):
297 def get_by_username(cls, username, case_insensitive=False, cache=False):
298 if case_insensitive:
298 if case_insensitive:
299 q = cls.query().filter(cls.username.ilike(username))
299 q = cls.query().filter(cls.username.ilike(username))
300 else:
300 else:
301 q = cls.query().filter(cls.username == username)
301 q = cls.query().filter(cls.username == username)
302
302
303 if cache:
303 if cache:
304 q = q.options(FromCache(
304 q = q.options(FromCache(
305 "sql_cache_short",
305 "sql_cache_short",
306 "get_user_%s" % _hash_key(username)
306 "get_user_%s" % _hash_key(username)
307 )
307 )
308 )
308 )
309 return q.scalar()
309 return q.scalar()
310
310
311 @classmethod
311 @classmethod
312 def get_by_auth_token(cls, auth_token, cache=False):
312 def get_by_auth_token(cls, auth_token, cache=False):
313 q = cls.query().filter(cls.api_key == auth_token)
313 q = cls.query().filter(cls.api_key == auth_token)
314
314
315 if cache:
315 if cache:
316 q = q.options(FromCache("sql_cache_short",
316 q = q.options(FromCache("sql_cache_short",
317 "get_auth_token_%s" % auth_token))
317 "get_auth_token_%s" % auth_token))
318 return q.scalar()
318 return q.scalar()
319
319
320 @classmethod
320 @classmethod
321 def get_by_email(cls, email, case_insensitive=False, cache=False):
321 def get_by_email(cls, email, case_insensitive=False, cache=False):
322 if case_insensitive:
322 if case_insensitive:
323 q = cls.query().filter(cls.email.ilike(email))
323 q = cls.query().filter(cls.email.ilike(email))
324 else:
324 else:
325 q = cls.query().filter(cls.email == email)
325 q = cls.query().filter(cls.email == email)
326
326
327 if cache:
327 if cache:
328 q = q.options(FromCache("sql_cache_short",
328 q = q.options(FromCache("sql_cache_short",
329 "get_email_key_%s" % email))
329 "get_email_key_%s" % email))
330
330
331 ret = q.scalar()
331 ret = q.scalar()
332 if ret is None:
332 if ret is None:
333 q = UserEmailMap.query()
333 q = UserEmailMap.query()
334 # try fetching in alternate email map
334 # try fetching in alternate email map
335 if case_insensitive:
335 if case_insensitive:
336 q = q.filter(UserEmailMap.email.ilike(email))
336 q = q.filter(UserEmailMap.email.ilike(email))
337 else:
337 else:
338 q = q.filter(UserEmailMap.email == email)
338 q = q.filter(UserEmailMap.email == email)
339 q = q.options(joinedload(UserEmailMap.user))
339 q = q.options(joinedload(UserEmailMap.user))
340 if cache:
340 if cache:
341 q = q.options(FromCache("sql_cache_short",
341 q = q.options(FromCache("sql_cache_short",
342 "get_email_map_key_%s" % email))
342 "get_email_map_key_%s" % email))
343 ret = getattr(q.scalar(), 'user', None)
343 ret = getattr(q.scalar(), 'user', None)
344
344
345 return ret
345 return ret
346
346
347
347
348 class UserEmailMap(Base, BaseModel):
348 class UserEmailMap(Base, BaseModel):
349 __tablename__ = 'user_email_map'
349 __tablename__ = 'user_email_map'
350 __table_args__ = (
350 __table_args__ = (
351 Index('uem_email_idx', 'email'),
351 Index('uem_email_idx', 'email'),
352 UniqueConstraint('email'),
352 UniqueConstraint('email'),
353 {'extend_existing': True, 'mysql_engine': 'InnoDB',
353 {'extend_existing': True, 'mysql_engine': 'InnoDB',
354 'mysql_charset': 'utf8'}
354 'mysql_charset': 'utf8'}
355 )
355 )
356 __mapper_args__ = {}
356 __mapper_args__ = {}
357
357
358 email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
358 email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
359 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
359 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
360 _email = Column("email", String(255), nullable=True, unique=False, default=None)
360 _email = Column("email", String(255), nullable=True, unique=False, default=None)
361 user = relationship('User', lazy='joined')
361 user = relationship('User', lazy='joined')
362
362
363 @validates('_email')
363 @validates('_email')
364 def validate_email(self, key, email):
364 def validate_email(self, key, email):
365 # check if this email is not main one
365 # check if this email is not main one
366 main_email = Session().query(User).filter(User.email == email).scalar()
366 main_email = Session().query(User).filter(User.email == email).scalar()
367 if main_email is not None:
367 if main_email is not None:
368 raise AttributeError('email %s is present is user table' % email)
368 raise AttributeError('email %s is present is user table' % email)
369 return email
369 return email
370
370
371 @hybrid_property
371 @hybrid_property
372 def email(self):
372 def email(self):
373 return self._email
373 return self._email
374
374
375 @email.setter
375 @email.setter
376 def email(self, val):
376 def email(self, val):
377 self._email = val.lower() if val else None
377 self._email = val.lower() if val else None
378
378
379
379
380 class UserLog(Base, BaseModel):
380 class UserLog(Base, BaseModel):
381 __tablename__ = 'user_logs'
381 __tablename__ = 'user_logs'
382 __table_args__ = (
382 __table_args__ = (
383 {'extend_existing': True, 'mysql_engine': 'InnoDB',
383 {'extend_existing': True, 'mysql_engine': 'InnoDB',
384 'mysql_charset': 'utf8'},
384 'mysql_charset': 'utf8'},
385 )
385 )
386 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
386 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
387 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
387 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
388 username = Column("username", String(255), nullable=True, unique=None, default=None)
388 username = Column("username", String(255), nullable=True, unique=None, default=None)
389 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
389 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
390 repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None)
390 repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None)
391 user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None)
391 user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None)
392 action = Column("action", String(1200000), nullable=True, unique=None, default=None)
392 action = Column("action", String(1200000), nullable=True, unique=None, default=None)
393 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
393 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
394
394
395
395
396 user = relationship('User')
396 user = relationship('User')
397 repository = relationship('Repository', cascade='')
397 repository = relationship('Repository', cascade='')
398
398
399
399
400 class UserGroup(Base, BaseModel):
400 class UserGroup(Base, BaseModel):
401 __tablename__ = 'users_groups'
401 __tablename__ = 'users_groups'
402 __table_args__ = (
402 __table_args__ = (
403 {'extend_existing': True, 'mysql_engine': 'InnoDB',
403 {'extend_existing': True, 'mysql_engine': 'InnoDB',
404 'mysql_charset': 'utf8'},
404 'mysql_charset': 'utf8'},
405 )
405 )
406
406
407 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
407 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
408 users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None)
408 users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None)
409 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
409 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
410 inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
410 inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
411
411
412 members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
412 members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
413 users_group_to_perm = relationship('UserGroupToPerm', cascade='all')
413 users_group_to_perm = relationship('UserGroupToPerm', cascade='all')
414 users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
414 users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
415
415
416 def __unicode__(self):
416 def __unicode__(self):
417 return u'<userGroup(%s)>' % (self.users_group_name)
417 return u'<userGroup(%s)>' % (self.users_group_name)
418
418
419 @classmethod
419 @classmethod
420 def get_by_group_name(cls, group_name, cache=False,
420 def get_by_group_name(cls, group_name, cache=False,
421 case_insensitive=False):
421 case_insensitive=False):
422 if case_insensitive:
422 if case_insensitive:
423 q = cls.query().filter(cls.users_group_name.ilike(group_name))
423 q = cls.query().filter(cls.users_group_name.ilike(group_name))
424 else:
424 else:
425 q = cls.query().filter(cls.users_group_name == group_name)
425 q = cls.query().filter(cls.users_group_name == group_name)
426 if cache:
426 if cache:
427 q = q.options(FromCache(
427 q = q.options(FromCache(
428 "sql_cache_short",
428 "sql_cache_short",
429 "get_user_%s" % _hash_key(group_name)
429 "get_user_%s" % _hash_key(group_name)
430 )
430 )
431 )
431 )
432 return q.scalar()
432 return q.scalar()
433
433
434 @classmethod
434 @classmethod
435 def get(cls, users_group_id, cache=False):
435 def get(cls, users_group_id, cache=False):
436 user_group = cls.query()
436 user_group = cls.query()
437 if cache:
437 if cache:
438 user_group = user_group.options(FromCache("sql_cache_short",
438 user_group = user_group.options(FromCache("sql_cache_short",
439 "get_users_group_%s" % users_group_id))
439 "get_users_group_%s" % users_group_id))
440 return user_group.get(users_group_id)
440 return user_group.get(users_group_id)
441
441
442
442
443 class UserGroupMember(Base, BaseModel):
443 class UserGroupMember(Base, BaseModel):
444 __tablename__ = 'users_groups_members'
444 __tablename__ = 'users_groups_members'
445 __table_args__ = (
445 __table_args__ = (
446 {'extend_existing': True, 'mysql_engine': 'InnoDB',
446 {'extend_existing': True, 'mysql_engine': 'InnoDB',
447 'mysql_charset': 'utf8'},
447 'mysql_charset': 'utf8'},
448 )
448 )
449
449
450 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
450 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
451 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
451 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
452 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
452 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
453
453
454 user = relationship('User', lazy='joined')
454 user = relationship('User', lazy='joined')
455 users_group = relationship('UserGroup')
455 users_group = relationship('UserGroup')
456
456
457 def __init__(self, gr_id='', u_id=''):
457 def __init__(self, gr_id='', u_id=''):
458 self.users_group_id = gr_id
458 self.users_group_id = gr_id
459 self.user_id = u_id
459 self.user_id = u_id
460
460
461
461
462 class Repository(Base, BaseModel):
462 class Repository(Base, BaseModel):
463 __tablename__ = 'repositories'
463 __tablename__ = 'repositories'
464 __table_args__ = (
464 __table_args__ = (
465 UniqueConstraint('repo_name'),
465 UniqueConstraint('repo_name'),
466 Index('r_repo_name_idx', 'repo_name'),
466 Index('r_repo_name_idx', 'repo_name'),
467 {'extend_existing': True, 'mysql_engine': 'InnoDB',
467 {'extend_existing': True, 'mysql_engine': 'InnoDB',
468 'mysql_charset': 'utf8'},
468 'mysql_charset': 'utf8'},
469 )
469 )
470
470
471 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
471 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
472 repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None)
472 repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None)
473 clone_uri = Column("clone_uri", String(255), nullable=True, unique=False, default=None)
473 clone_uri = Column("clone_uri", String(255), nullable=True, unique=False, default=None)
474 repo_type = Column("repo_type", String(255), nullable=False, unique=False, default=None)
474 repo_type = Column("repo_type", String(255), nullable=False, unique=False, default=None)
475 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
475 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
476 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
476 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
477 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
477 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
478 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
478 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
479 description = Column("description", String(10000), nullable=True, unique=None, default=None)
479 description = Column("description", String(10000), nullable=True, unique=None, default=None)
480 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
480 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
481 updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
481 updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
482 landing_rev = Column("landing_revision", String(255), nullable=False, unique=False, default=None)
482 landing_rev = Column("landing_revision", String(255), nullable=False, unique=False, default=None)
483 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
483 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
484 _locked = Column("locked", String(255), nullable=True, unique=False, default=None)
484 _locked = Column("locked", String(255), nullable=True, unique=False, default=None)
485
485
486 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
486 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
487 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
487 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
488
488
489 user = relationship('User')
489 user = relationship('User')
490 fork = relationship('Repository', remote_side=repo_id)
490 fork = relationship('Repository', remote_side=repo_id)
491 group = relationship('RepoGroup')
491 group = relationship('RepoGroup')
492 repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
492 repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
493 users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
493 users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
494 stats = relationship('Statistics', cascade='all', uselist=False)
494 stats = relationship('Statistics', cascade='all', uselist=False)
495
495
496 followers = relationship('UserFollowing',
496 followers = relationship('UserFollowing',
497 primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id',
497 primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id',
498 cascade='all')
498 cascade='all')
499
499
500 logs = relationship('UserLog')
500 logs = relationship('UserLog')
501 comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan")
501 comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan")
502
502
503 pull_requests_org = relationship('PullRequest',
503 pull_requests_org = relationship('PullRequest',
504 primaryjoin='PullRequest.org_repo_id==Repository.repo_id',
504 primaryjoin='PullRequest.org_repo_id==Repository.repo_id',
505 cascade="all, delete, delete-orphan")
505 cascade="all, delete, delete-orphan")
506
506
507 pull_requests_other = relationship('PullRequest',
507 pull_requests_other = relationship('PullRequest',
508 primaryjoin='PullRequest.other_repo_id==Repository.repo_id',
508 primaryjoin='PullRequest.other_repo_id==Repository.repo_id',
509 cascade="all, delete, delete-orphan")
509 cascade="all, delete, delete-orphan")
510
510
511 def __unicode__(self):
511 def __unicode__(self):
512 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id,
512 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id,
513 self.repo_name)
513 self.repo_name)
514
514
515
515
516 @classmethod
516 @classmethod
517 def get_by_repo_name(cls, repo_name):
517 def get_by_repo_name(cls, repo_name):
518 q = Session().query(cls).filter(cls.repo_name == repo_name)
518 q = Session().query(cls).filter(cls.repo_name == repo_name)
519 q = q.options(joinedload(Repository.fork))\
519 q = q.options(joinedload(Repository.fork))\
520 .options(joinedload(Repository.user))\
520 .options(joinedload(Repository.user))\
521 .options(joinedload(Repository.group))
521 .options(joinedload(Repository.group))
522 return q.scalar()
522 return q.scalar()
523
523
524
524
525 class RepoGroup(Base, BaseModel):
525 class RepoGroup(Base, BaseModel):
526 __tablename__ = 'groups'
526 __tablename__ = 'groups'
527 __table_args__ = (
527 __table_args__ = (
528 UniqueConstraint('group_name', 'group_parent_id'),
528 UniqueConstraint('group_name', 'group_parent_id'),
529 CheckConstraint('group_id != group_parent_id'),
530 {'extend_existing': True, 'mysql_engine': 'InnoDB',
529 {'extend_existing': True, 'mysql_engine': 'InnoDB',
531 'mysql_charset': 'utf8'},
530 'mysql_charset': 'utf8'},
532 )
531 )
533 __mapper_args__ = {'order_by': 'group_name'}
532 __mapper_args__ = {'order_by': 'group_name'}
534
533
535 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
534 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
536 group_name = Column("group_name", String(255), nullable=False, unique=True, default=None)
535 group_name = Column("group_name", String(255), nullable=False, unique=True, default=None)
537 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
536 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
538 group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None)
537 group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None)
539 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
538 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
540
539
541 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
540 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
542 users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
541 users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
543 parent_group = relationship('RepoGroup', remote_side=group_id)
542 parent_group = relationship('RepoGroup', remote_side=group_id)
544
543
545 def __init__(self, group_name='', parent_group=None):
544 def __init__(self, group_name='', parent_group=None):
546 self.group_name = group_name
545 self.group_name = group_name
547 self.parent_group = parent_group
546 self.parent_group = parent_group
548
547
549 def __unicode__(self):
548 def __unicode__(self):
550 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
549 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
551 self.group_name)
550 self.group_name)
552
551
553 @classmethod
552 @classmethod
554 def url_sep(cls):
553 def url_sep(cls):
555 return URL_SEP
554 return URL_SEP
556
555
557 @classmethod
556 @classmethod
558 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
557 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
559 if case_insensitive:
558 if case_insensitive:
560 gr = cls.query()\
559 gr = cls.query()\
561 .filter(cls.group_name.ilike(group_name))
560 .filter(cls.group_name.ilike(group_name))
562 else:
561 else:
563 gr = cls.query()\
562 gr = cls.query()\
564 .filter(cls.group_name == group_name)
563 .filter(cls.group_name == group_name)
565 if cache:
564 if cache:
566 gr = gr.options(FromCache(
565 gr = gr.options(FromCache(
567 "sql_cache_short",
566 "sql_cache_short",
568 "get_group_%s" % _hash_key(group_name)
567 "get_group_%s" % _hash_key(group_name)
569 )
568 )
570 )
569 )
571 return gr.scalar()
570 return gr.scalar()
572
571
573
572
574 class Permission(Base, BaseModel):
573 class Permission(Base, BaseModel):
575 __tablename__ = 'permissions'
574 __tablename__ = 'permissions'
576 __table_args__ = (
575 __table_args__ = (
577 Index('p_perm_name_idx', 'permission_name'),
576 Index('p_perm_name_idx', 'permission_name'),
578 {'extend_existing': True, 'mysql_engine': 'InnoDB',
577 {'extend_existing': True, 'mysql_engine': 'InnoDB',
579 'mysql_charset': 'utf8'},
578 'mysql_charset': 'utf8'},
580 )
579 )
581 PERMS = [
580 PERMS = [
582 ('repository.none', _('Repository no access')),
581 ('repository.none', _('Repository no access')),
583 ('repository.read', _('Repository read access')),
582 ('repository.read', _('Repository read access')),
584 ('repository.write', _('Repository write access')),
583 ('repository.write', _('Repository write access')),
585 ('repository.admin', _('Repository admin access')),
584 ('repository.admin', _('Repository admin access')),
586
585
587 ('group.none', _('Repositories Group no access')),
586 ('group.none', _('Repositories Group no access')),
588 ('group.read', _('Repositories Group read access')),
587 ('group.read', _('Repositories Group read access')),
589 ('group.write', _('Repositories Group write access')),
588 ('group.write', _('Repositories Group write access')),
590 ('group.admin', _('Repositories Group admin access')),
589 ('group.admin', _('Repositories Group admin access')),
591
590
592 ('hg.admin', _('RhodeCode Administrator')),
591 ('hg.admin', _('RhodeCode Administrator')),
593 ('hg.create.none', _('Repository creation disabled')),
592 ('hg.create.none', _('Repository creation disabled')),
594 ('hg.create.repository', _('Repository creation enabled')),
593 ('hg.create.repository', _('Repository creation enabled')),
595 ('hg.fork.none', _('Repository forking disabled')),
594 ('hg.fork.none', _('Repository forking disabled')),
596 ('hg.fork.repository', _('Repository forking enabled')),
595 ('hg.fork.repository', _('Repository forking enabled')),
597 ('hg.register.none', _('Register disabled')),
596 ('hg.register.none', _('Register disabled')),
598 ('hg.register.manual_activate', _('Register new user with RhodeCode '
597 ('hg.register.manual_activate', _('Register new user with RhodeCode '
599 'with manual activation')),
598 'with manual activation')),
600
599
601 ('hg.register.auto_activate', _('Register new user with RhodeCode '
600 ('hg.register.auto_activate', _('Register new user with RhodeCode '
602 'with auto activation')),
601 'with auto activation')),
603 ]
602 ]
604
603
605 # defines which permissions are more important higher the more important
604 # defines which permissions are more important higher the more important
606 PERM_WEIGHTS = {
605 PERM_WEIGHTS = {
607 'repository.none': 0,
606 'repository.none': 0,
608 'repository.read': 1,
607 'repository.read': 1,
609 'repository.write': 3,
608 'repository.write': 3,
610 'repository.admin': 4,
609 'repository.admin': 4,
611
610
612 'group.none': 0,
611 'group.none': 0,
613 'group.read': 1,
612 'group.read': 1,
614 'group.write': 3,
613 'group.write': 3,
615 'group.admin': 4,
614 'group.admin': 4,
616
615
617 'hg.fork.none': 0,
616 'hg.fork.none': 0,
618 'hg.fork.repository': 1,
617 'hg.fork.repository': 1,
619 'hg.create.none': 0,
618 'hg.create.none': 0,
620 'hg.create.repository':1
619 'hg.create.repository':1
621 }
620 }
622
621
623 DEFAULT_USER_PERMISSIONS = [
622 DEFAULT_USER_PERMISSIONS = [
624 'repository.read',
623 'repository.read',
625 'group.read',
624 'group.read',
626 'hg.create.repository',
625 'hg.create.repository',
627 'hg.fork.repository',
626 'hg.fork.repository',
628 'hg.register.manual_activate',
627 'hg.register.manual_activate',
629 ]
628 ]
630
629
631 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
630 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
632 permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None)
631 permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None)
633 permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None)
632 permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None)
634
633
635 def __unicode__(self):
634 def __unicode__(self):
636 return u"<%s('%s:%s')>" % (
635 return u"<%s('%s:%s')>" % (
637 self.__class__.__name__, self.permission_id, self.permission_name
636 self.__class__.__name__, self.permission_id, self.permission_name
638 )
637 )
639
638
640 @classmethod
639 @classmethod
641 def get_by_key(cls, key):
640 def get_by_key(cls, key):
642 return cls.query().filter(cls.permission_name == key).scalar()
641 return cls.query().filter(cls.permission_name == key).scalar()
643
642
644
643
645 class UserRepoToPerm(Base, BaseModel):
644 class UserRepoToPerm(Base, BaseModel):
646 __tablename__ = 'repo_to_perm'
645 __tablename__ = 'repo_to_perm'
647 __table_args__ = (
646 __table_args__ = (
648 UniqueConstraint('user_id', 'repository_id', 'permission_id'),
647 UniqueConstraint('user_id', 'repository_id', 'permission_id'),
649 {'extend_existing': True, 'mysql_engine': 'InnoDB',
648 {'extend_existing': True, 'mysql_engine': 'InnoDB',
650 'mysql_charset': 'utf8'}
649 'mysql_charset': 'utf8'}
651 )
650 )
652 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
651 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
653 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
652 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
654 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
653 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
655 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
654 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
656
655
657 user = relationship('User')
656 user = relationship('User')
658 repository = relationship('Repository')
657 repository = relationship('Repository')
659 permission = relationship('Permission')
658 permission = relationship('Permission')
660
659
661 def __unicode__(self):
660 def __unicode__(self):
662 return u'<user:%s => %s >' % (self.user, self.repository)
661 return u'<user:%s => %s >' % (self.user, self.repository)
663
662
664
663
665 class UserToPerm(Base, BaseModel):
664 class UserToPerm(Base, BaseModel):
666 __tablename__ = 'user_to_perm'
665 __tablename__ = 'user_to_perm'
667 __table_args__ = (
666 __table_args__ = (
668 UniqueConstraint('user_id', 'permission_id'),
667 UniqueConstraint('user_id', 'permission_id'),
669 {'extend_existing': True, 'mysql_engine': 'InnoDB',
668 {'extend_existing': True, 'mysql_engine': 'InnoDB',
670 'mysql_charset': 'utf8'}
669 'mysql_charset': 'utf8'}
671 )
670 )
672 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
671 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
673 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
672 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
674 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
673 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
675
674
676 user = relationship('User')
675 user = relationship('User')
677 permission = relationship('Permission', lazy='joined')
676 permission = relationship('Permission', lazy='joined')
678
677
679
678
680 class UserGroupRepoToPerm(Base, BaseModel):
679 class UserGroupRepoToPerm(Base, BaseModel):
681 __tablename__ = 'users_group_repo_to_perm'
680 __tablename__ = 'users_group_repo_to_perm'
682 __table_args__ = (
681 __table_args__ = (
683 UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
682 UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
684 {'extend_existing': True, 'mysql_engine': 'InnoDB',
683 {'extend_existing': True, 'mysql_engine': 'InnoDB',
685 'mysql_charset': 'utf8'}
684 'mysql_charset': 'utf8'}
686 )
685 )
687 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
686 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
688 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
687 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
689 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
688 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
690 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
689 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
691
690
692 users_group = relationship('UserGroup')
691 users_group = relationship('UserGroup')
693 permission = relationship('Permission')
692 permission = relationship('Permission')
694 repository = relationship('Repository')
693 repository = relationship('Repository')
695
694
696 def __unicode__(self):
695 def __unicode__(self):
697 return u'<userGroup:%s => %s >' % (self.users_group, self.repository)
696 return u'<userGroup:%s => %s >' % (self.users_group, self.repository)
698
697
699
698
700 class UserGroupToPerm(Base, BaseModel):
699 class UserGroupToPerm(Base, BaseModel):
701 __tablename__ = 'users_group_to_perm'
700 __tablename__ = 'users_group_to_perm'
702 __table_args__ = (
701 __table_args__ = (
703 UniqueConstraint('users_group_id', 'permission_id',),
702 UniqueConstraint('users_group_id', 'permission_id',),
704 {'extend_existing': True, 'mysql_engine': 'InnoDB',
703 {'extend_existing': True, 'mysql_engine': 'InnoDB',
705 'mysql_charset': 'utf8'}
704 'mysql_charset': 'utf8'}
706 )
705 )
707 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
706 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
708 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
707 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
709 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
708 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
710
709
711 users_group = relationship('UserGroup')
710 users_group = relationship('UserGroup')
712 permission = relationship('Permission')
711 permission = relationship('Permission')
713
712
714
713
715 class UserRepoGroupToPerm(Base, BaseModel):
714 class UserRepoGroupToPerm(Base, BaseModel):
716 __tablename__ = 'user_repo_group_to_perm'
715 __tablename__ = 'user_repo_group_to_perm'
717 __table_args__ = (
716 __table_args__ = (
718 UniqueConstraint('user_id', 'group_id', 'permission_id'),
717 UniqueConstraint('user_id', 'group_id', 'permission_id'),
719 {'extend_existing': True, 'mysql_engine': 'InnoDB',
718 {'extend_existing': True, 'mysql_engine': 'InnoDB',
720 'mysql_charset': 'utf8'}
719 'mysql_charset': 'utf8'}
721 )
720 )
722
721
723 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
722 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
724 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
723 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
725 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
724 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
726 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
725 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
727
726
728 user = relationship('User')
727 user = relationship('User')
729 group = relationship('RepoGroup')
728 group = relationship('RepoGroup')
730 permission = relationship('Permission')
729 permission = relationship('Permission')
731
730
732
731
733 class UserGroupRepoGroupToPerm(Base, BaseModel):
732 class UserGroupRepoGroupToPerm(Base, BaseModel):
734 __tablename__ = 'users_group_repo_group_to_perm'
733 __tablename__ = 'users_group_repo_group_to_perm'
735 __table_args__ = (
734 __table_args__ = (
736 UniqueConstraint('users_group_id', 'group_id'),
735 UniqueConstraint('users_group_id', 'group_id'),
737 {'extend_existing': True, 'mysql_engine': 'InnoDB',
736 {'extend_existing': True, 'mysql_engine': 'InnoDB',
738 'mysql_charset': 'utf8'}
737 'mysql_charset': 'utf8'}
739 )
738 )
740
739
741 users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
740 users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
742 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
741 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
743 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
742 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
744 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
743 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
745
744
746 users_group = relationship('UserGroup')
745 users_group = relationship('UserGroup')
747 permission = relationship('Permission')
746 permission = relationship('Permission')
748 group = relationship('RepoGroup')
747 group = relationship('RepoGroup')
749
748
750
749
751 class Statistics(Base, BaseModel):
750 class Statistics(Base, BaseModel):
752 __tablename__ = 'statistics'
751 __tablename__ = 'statistics'
753 __table_args__ = (
752 __table_args__ = (
754 UniqueConstraint('repository_id'),
753 UniqueConstraint('repository_id'),
755 {'extend_existing': True, 'mysql_engine': 'InnoDB',
754 {'extend_existing': True, 'mysql_engine': 'InnoDB',
756 'mysql_charset': 'utf8'}
755 'mysql_charset': 'utf8'}
757 )
756 )
758 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
757 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
759 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
758 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
760 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
759 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
761 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
760 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
762 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
761 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
763 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
762 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
764
763
765 repository = relationship('Repository', single_parent=True)
764 repository = relationship('Repository', single_parent=True)
766
765
767
766
768 class UserFollowing(Base, BaseModel):
767 class UserFollowing(Base, BaseModel):
769 __tablename__ = 'user_followings'
768 __tablename__ = 'user_followings'
770 __table_args__ = (
769 __table_args__ = (
771 UniqueConstraint('user_id', 'follows_repository_id'),
770 UniqueConstraint('user_id', 'follows_repository_id'),
772 UniqueConstraint('user_id', 'follows_user_id'),
771 UniqueConstraint('user_id', 'follows_user_id'),
773 {'extend_existing': True, 'mysql_engine': 'InnoDB',
772 {'extend_existing': True, 'mysql_engine': 'InnoDB',
774 'mysql_charset': 'utf8'}
773 'mysql_charset': 'utf8'}
775 )
774 )
776
775
777 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
776 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
778 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
777 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
779 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
778 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
780 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
779 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
781 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
780 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
782
781
783 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
782 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
784
783
785 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
784 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
786 follows_repository = relationship('Repository', order_by='Repository.repo_name')
785 follows_repository = relationship('Repository', order_by='Repository.repo_name')
787
786
788
787
789 class CacheInvalidation(Base, BaseModel):
788 class CacheInvalidation(Base, BaseModel):
790 __tablename__ = 'cache_invalidation'
789 __tablename__ = 'cache_invalidation'
791 __table_args__ = (
790 __table_args__ = (
792 UniqueConstraint('cache_key'),
791 UniqueConstraint('cache_key'),
793 Index('key_idx', 'cache_key'),
792 Index('key_idx', 'cache_key'),
794 {'extend_existing': True, 'mysql_engine': 'InnoDB',
793 {'extend_existing': True, 'mysql_engine': 'InnoDB',
795 'mysql_charset': 'utf8'},
794 'mysql_charset': 'utf8'},
796 )
795 )
797 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
796 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
798 cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None)
797 cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None)
799 cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None)
798 cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None)
800 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
799 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
801
800
802 def __init__(self, cache_key, cache_args=''):
801 def __init__(self, cache_key, cache_args=''):
803 self.cache_key = cache_key
802 self.cache_key = cache_key
804 self.cache_args = cache_args
803 self.cache_args = cache_args
805 self.cache_active = False
804 self.cache_active = False
806
805
807
806
808 class ChangesetComment(Base, BaseModel):
807 class ChangesetComment(Base, BaseModel):
809 __tablename__ = 'changeset_comments'
808 __tablename__ = 'changeset_comments'
810 __table_args__ = (
809 __table_args__ = (
811 Index('cc_revision_idx', 'revision'),
810 Index('cc_revision_idx', 'revision'),
812 {'extend_existing': True, 'mysql_engine': 'InnoDB',
811 {'extend_existing': True, 'mysql_engine': 'InnoDB',
813 'mysql_charset': 'utf8'},
812 'mysql_charset': 'utf8'},
814 )
813 )
815 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
814 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
816 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
815 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
817 revision = Column('revision', String(40), nullable=True)
816 revision = Column('revision', String(40), nullable=True)
818 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
817 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
819 line_no = Column('line_no', Unicode(10), nullable=True)
818 line_no = Column('line_no', Unicode(10), nullable=True)
820 hl_lines = Column('hl_lines', Unicode(512), nullable=True)
819 hl_lines = Column('hl_lines', Unicode(512), nullable=True)
821 f_path = Column('f_path', Unicode(1000), nullable=True)
820 f_path = Column('f_path', Unicode(1000), nullable=True)
822 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
821 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
823 text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False)
822 text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False)
824 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
823 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
825 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
824 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
826
825
827 author = relationship('User', lazy='joined')
826 author = relationship('User', lazy='joined')
828 repo = relationship('Repository')
827 repo = relationship('Repository')
829 status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan")
828 status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan")
830 pull_request = relationship('PullRequest', lazy='joined')
829 pull_request = relationship('PullRequest', lazy='joined')
831
830
832 @classmethod
831 @classmethod
833 def get_users(cls, revision=None, pull_request_id=None):
832 def get_users(cls, revision=None, pull_request_id=None):
834 """
833 """
835 Returns user associated with this ChangesetComment. ie those
834 Returns user associated with this ChangesetComment. ie those
836 who actually commented
835 who actually commented
837
836
838 :param cls:
837 :param cls:
839 :param revision:
838 :param revision:
840 """
839 """
841 q = Session().query(User)\
840 q = Session().query(User)\
842 .join(ChangesetComment.author)
841 .join(ChangesetComment.author)
843 if revision:
842 if revision:
844 q = q.filter(cls.revision == revision)
843 q = q.filter(cls.revision == revision)
845 elif pull_request_id:
844 elif pull_request_id:
846 q = q.filter(cls.pull_request_id == pull_request_id)
845 q = q.filter(cls.pull_request_id == pull_request_id)
847 return q.all()
846 return q.all()
848
847
849
848
850 class ChangesetStatus(Base, BaseModel):
849 class ChangesetStatus(Base, BaseModel):
851 __tablename__ = 'changeset_statuses'
850 __tablename__ = 'changeset_statuses'
852 __table_args__ = (
851 __table_args__ = (
853 Index('cs_revision_idx', 'revision'),
852 Index('cs_revision_idx', 'revision'),
854 Index('cs_version_idx', 'version'),
853 Index('cs_version_idx', 'version'),
855 UniqueConstraint('repo_id', 'revision', 'version'),
854 UniqueConstraint('repo_id', 'revision', 'version'),
856 {'extend_existing': True, 'mysql_engine': 'InnoDB',
855 {'extend_existing': True, 'mysql_engine': 'InnoDB',
857 'mysql_charset': 'utf8'}
856 'mysql_charset': 'utf8'}
858 )
857 )
859 STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed'
858 STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed'
860 STATUS_APPROVED = 'approved'
859 STATUS_APPROVED = 'approved'
861 STATUS_REJECTED = 'rejected'
860 STATUS_REJECTED = 'rejected'
862 STATUS_UNDER_REVIEW = 'under_review'
861 STATUS_UNDER_REVIEW = 'under_review'
863
862
864 STATUSES = [
863 STATUSES = [
865 (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default
864 (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default
866 (STATUS_APPROVED, _("Approved")),
865 (STATUS_APPROVED, _("Approved")),
867 (STATUS_REJECTED, _("Rejected")),
866 (STATUS_REJECTED, _("Rejected")),
868 (STATUS_UNDER_REVIEW, _("Under Review")),
867 (STATUS_UNDER_REVIEW, _("Under Review")),
869 ]
868 ]
870
869
871 changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True)
870 changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True)
872 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
871 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
873 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
872 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
874 revision = Column('revision', String(40), nullable=False)
873 revision = Column('revision', String(40), nullable=False)
875 status = Column('status', String(128), nullable=False, default=DEFAULT)
874 status = Column('status', String(128), nullable=False, default=DEFAULT)
876 changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id'))
875 changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id'))
877 modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
876 modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
878 version = Column('version', Integer(), nullable=False, default=0)
877 version = Column('version', Integer(), nullable=False, default=0)
879 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
878 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
880
879
881 author = relationship('User', lazy='joined')
880 author = relationship('User', lazy='joined')
882 repo = relationship('Repository')
881 repo = relationship('Repository')
883 comment = relationship('ChangesetComment', lazy='joined')
882 comment = relationship('ChangesetComment', lazy='joined')
884 pull_request = relationship('PullRequest', lazy='joined')
883 pull_request = relationship('PullRequest', lazy='joined')
885
884
886
885
887
886
888 class PullRequest(Base, BaseModel):
887 class PullRequest(Base, BaseModel):
889 __tablename__ = 'pull_requests'
888 __tablename__ = 'pull_requests'
890 __table_args__ = (
889 __table_args__ = (
891 {'extend_existing': True, 'mysql_engine': 'InnoDB',
890 {'extend_existing': True, 'mysql_engine': 'InnoDB',
892 'mysql_charset': 'utf8'},
891 'mysql_charset': 'utf8'},
893 )
892 )
894
893
895 STATUS_NEW = u'new'
894 STATUS_NEW = u'new'
896 STATUS_OPEN = u'open'
895 STATUS_OPEN = u'open'
897 STATUS_CLOSED = u'closed'
896 STATUS_CLOSED = u'closed'
898
897
899 pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True)
898 pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True)
900 title = Column('title', Unicode(256), nullable=True)
899 title = Column('title', Unicode(256), nullable=True)
901 description = Column('description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), nullable=True)
900 description = Column('description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), nullable=True)
902 status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW)
901 status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW)
903 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
902 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
904 updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
903 updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
905 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
904 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
906 _revisions = Column('revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql'))
905 _revisions = Column('revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql'))
907 org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
906 org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
908 org_ref = Column('org_ref', Unicode(256), nullable=False)
907 org_ref = Column('org_ref', Unicode(256), nullable=False)
909 other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
908 other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
910 other_ref = Column('other_ref', Unicode(256), nullable=False)
909 other_ref = Column('other_ref', Unicode(256), nullable=False)
911
910
912 author = relationship('User', lazy='joined')
911 author = relationship('User', lazy='joined')
913 reviewers = relationship('PullRequestReviewers',
912 reviewers = relationship('PullRequestReviewers',
914 cascade="all, delete, delete-orphan")
913 cascade="all, delete, delete-orphan")
915 org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id')
914 org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id')
916 other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id')
915 other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id')
917 statuses = relationship('ChangesetStatus')
916 statuses = relationship('ChangesetStatus')
918 comments = relationship('ChangesetComment',
917 comments = relationship('ChangesetComment',
919 cascade="all, delete, delete-orphan")
918 cascade="all, delete, delete-orphan")
920
919
921
920
922 class PullRequestReviewers(Base, BaseModel):
921 class PullRequestReviewers(Base, BaseModel):
923 __tablename__ = 'pull_request_reviewers'
922 __tablename__ = 'pull_request_reviewers'
924 __table_args__ = (
923 __table_args__ = (
925 {'extend_existing': True, 'mysql_engine': 'InnoDB',
924 {'extend_existing': True, 'mysql_engine': 'InnoDB',
926 'mysql_charset': 'utf8'},
925 'mysql_charset': 'utf8'},
927 )
926 )
928
927
929 def __init__(self, user=None, pull_request=None):
928 def __init__(self, user=None, pull_request=None):
930 self.user = user
929 self.user = user
931 self.pull_request = pull_request
930 self.pull_request = pull_request
932
931
933 pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True)
932 pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True)
934 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False)
933 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False)
935 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True)
934 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True)
936
935
937 user = relationship('User')
936 user = relationship('User')
938 pull_request = relationship('PullRequest')
937 pull_request = relationship('PullRequest')
939
938
940
939
941 class Notification(Base, BaseModel):
940 class Notification(Base, BaseModel):
942 __tablename__ = 'notifications'
941 __tablename__ = 'notifications'
943 __table_args__ = (
942 __table_args__ = (
944 Index('notification_type_idx', 'type'),
943 Index('notification_type_idx', 'type'),
945 {'extend_existing': True, 'mysql_engine': 'InnoDB',
944 {'extend_existing': True, 'mysql_engine': 'InnoDB',
946 'mysql_charset': 'utf8'},
945 'mysql_charset': 'utf8'},
947 )
946 )
948
947
949 TYPE_CHANGESET_COMMENT = u'cs_comment'
948 TYPE_CHANGESET_COMMENT = u'cs_comment'
950 TYPE_MESSAGE = u'message'
949 TYPE_MESSAGE = u'message'
951 TYPE_MENTION = u'mention'
950 TYPE_MENTION = u'mention'
952 TYPE_REGISTRATION = u'registration'
951 TYPE_REGISTRATION = u'registration'
953 TYPE_PULL_REQUEST = u'pull_request'
952 TYPE_PULL_REQUEST = u'pull_request'
954 TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment'
953 TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment'
955
954
956 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
955 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
957 subject = Column('subject', Unicode(512), nullable=True)
956 subject = Column('subject', Unicode(512), nullable=True)
958 body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True)
957 body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True)
959 created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
958 created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
960 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
959 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
961 type_ = Column('type', Unicode(256))
960 type_ = Column('type', Unicode(256))
962
961
963 created_by_user = relationship('User')
962 created_by_user = relationship('User')
964 notifications_to_users = relationship('UserNotification', lazy='joined',
963 notifications_to_users = relationship('UserNotification', lazy='joined',
965 cascade="all, delete, delete-orphan")
964 cascade="all, delete, delete-orphan")
966
965
967
966
968 class UserNotification(Base, BaseModel):
967 class UserNotification(Base, BaseModel):
969 __tablename__ = 'user_to_notification'
968 __tablename__ = 'user_to_notification'
970 __table_args__ = (
969 __table_args__ = (
971 UniqueConstraint('user_id', 'notification_id'),
970 UniqueConstraint('user_id', 'notification_id'),
972 {'extend_existing': True, 'mysql_engine': 'InnoDB',
971 {'extend_existing': True, 'mysql_engine': 'InnoDB',
973 'mysql_charset': 'utf8'}
972 'mysql_charset': 'utf8'}
974 )
973 )
975 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
974 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
976 notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
975 notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
977 read = Column('read', Boolean, default=False)
976 read = Column('read', Boolean, default=False)
978 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
977 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
979
978
980 user = relationship('User', lazy="joined")
979 user = relationship('User', lazy="joined")
981 notification = relationship('Notification', lazy="joined",
980 notification = relationship('Notification', lazy="joined",
982 order_by=lambda: Notification.created_on.desc(),)
981 order_by=lambda: Notification.created_on.desc(),)
983
982
984
983
985 class DbMigrateVersion(Base, BaseModel):
984 class DbMigrateVersion(Base, BaseModel):
986 __tablename__ = 'db_migrate_version'
985 __tablename__ = 'db_migrate_version'
987 __table_args__ = (
986 __table_args__ = (
988 {'extend_existing': True, 'mysql_engine': 'InnoDB',
987 {'extend_existing': True, 'mysql_engine': 'InnoDB',
989 'mysql_charset': 'utf8'},
988 'mysql_charset': 'utf8'},
990 )
989 )
991 repository_id = Column('repository_id', String(250), primary_key=True)
990 repository_id = Column('repository_id', String(250), primary_key=True)
992 repository_path = Column('repository_path', Text)
991 repository_path = Column('repository_path', Text)
993 version = Column('version', Integer)
992 version = Column('version', Integer)
@@ -1,1002 +1,1001 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2019 RhodeCode GmbH
3 # Copyright (C) 2010-2019 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import os
21 import os
22 import time
22 import time
23 import logging
23 import logging
24 import datetime
24 import datetime
25 import traceback
25 import traceback
26 import hashlib
26 import hashlib
27 import collections
27 import collections
28
28
29 from sqlalchemy import *
29 from sqlalchemy import *
30 from sqlalchemy.ext.hybrid import hybrid_property
30 from sqlalchemy.ext.hybrid import hybrid_property
31 from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
31 from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
32 from sqlalchemy.exc import DatabaseError
32 from sqlalchemy.exc import DatabaseError
33 from beaker.cache import cache_region, region_invalidate
33 from beaker.cache import cache_region, region_invalidate
34 from webob.exc import HTTPNotFound
34 from webob.exc import HTTPNotFound
35
35
36 from rhodecode.translation import _
36 from rhodecode.translation import _
37
37
38 from rhodecode.lib.vcs import get_backend
38 from rhodecode.lib.vcs import get_backend
39 from rhodecode.lib.vcs.utils.helpers import get_scm
39 from rhodecode.lib.vcs.utils.helpers import get_scm
40 from rhodecode.lib.vcs.exceptions import VCSError
40 from rhodecode.lib.vcs.exceptions import VCSError
41 from zope.cachedescriptors.property import Lazy as LazyProperty
41 from zope.cachedescriptors.property import Lazy as LazyProperty
42 from rhodecode.lib.vcs.backends.base import EmptyCommit
42 from rhodecode.lib.vcs.backends.base import EmptyCommit
43
43
44 from rhodecode.lib.utils2 import str2bool, safe_str, get_commit_safe, \
44 from rhodecode.lib.utils2 import str2bool, safe_str, get_commit_safe, \
45 safe_unicode, remove_suffix, remove_prefix
45 safe_unicode, remove_suffix, remove_prefix
46 from rhodecode.lib.ext_json import json
46 from rhodecode.lib.ext_json import json
47 from rhodecode.lib.caching_query import FromCache
47 from rhodecode.lib.caching_query import FromCache
48
48
49 from rhodecode.model.meta import Base, Session
49 from rhodecode.model.meta import Base, Session
50
50
51 URL_SEP = '/'
51 URL_SEP = '/'
52 log = logging.getLogger(__name__)
52 log = logging.getLogger(__name__)
53
53
54 #==============================================================================
54 #==============================================================================
55 # BASE CLASSES
55 # BASE CLASSES
56 #==============================================================================
56 #==============================================================================
57
57
58 _hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest()
58 _hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest()
59
59
60
60
61 class BaseModel(object):
61 class BaseModel(object):
62 """
62 """
63 Base Model for all classes
63 Base Model for all classes
64 """
64 """
65
65
66 @classmethod
66 @classmethod
67 def _get_keys(cls):
67 def _get_keys(cls):
68 """return column names for this model """
68 """return column names for this model """
69 return class_mapper(cls).c.keys()
69 return class_mapper(cls).c.keys()
70
70
71 def get_dict(self):
71 def get_dict(self):
72 """
72 """
73 return dict with keys and values corresponding
73 return dict with keys and values corresponding
74 to this model data """
74 to this model data """
75
75
76 d = {}
76 d = {}
77 for k in self._get_keys():
77 for k in self._get_keys():
78 d[k] = getattr(self, k)
78 d[k] = getattr(self, k)
79
79
80 # also use __json__() if present to get additional fields
80 # also use __json__() if present to get additional fields
81 _json_attr = getattr(self, '__json__', None)
81 _json_attr = getattr(self, '__json__', None)
82 if _json_attr:
82 if _json_attr:
83 # update with attributes from __json__
83 # update with attributes from __json__
84 if callable(_json_attr):
84 if callable(_json_attr):
85 _json_attr = _json_attr()
85 _json_attr = _json_attr()
86 for k, val in _json_attr.iteritems():
86 for k, val in _json_attr.iteritems():
87 d[k] = val
87 d[k] = val
88 return d
88 return d
89
89
90 def get_appstruct(self):
90 def get_appstruct(self):
91 """return list with keys and values tupples corresponding
91 """return list with keys and values tupples corresponding
92 to this model data """
92 to this model data """
93
93
94 l = []
94 l = []
95 for k in self._get_keys():
95 for k in self._get_keys():
96 l.append((k, getattr(self, k),))
96 l.append((k, getattr(self, k),))
97 return l
97 return l
98
98
99 def populate_obj(self, populate_dict):
99 def populate_obj(self, populate_dict):
100 """populate model with data from given populate_dict"""
100 """populate model with data from given populate_dict"""
101
101
102 for k in self._get_keys():
102 for k in self._get_keys():
103 if k in populate_dict:
103 if k in populate_dict:
104 setattr(self, k, populate_dict[k])
104 setattr(self, k, populate_dict[k])
105
105
106 @classmethod
106 @classmethod
107 def query(cls):
107 def query(cls):
108 return Session().query(cls)
108 return Session().query(cls)
109
109
110 @classmethod
110 @classmethod
111 def get(cls, id_):
111 def get(cls, id_):
112 if id_:
112 if id_:
113 return cls.query().get(id_)
113 return cls.query().get(id_)
114
114
115 @classmethod
115 @classmethod
116 def get_or_404(cls, id_):
116 def get_or_404(cls, id_):
117 try:
117 try:
118 id_ = int(id_)
118 id_ = int(id_)
119 except (TypeError, ValueError):
119 except (TypeError, ValueError):
120 raise HTTPNotFound
120 raise HTTPNotFound
121
121
122 res = cls.query().get(id_)
122 res = cls.query().get(id_)
123 if not res:
123 if not res:
124 raise HTTPNotFound
124 raise HTTPNotFound
125 return res
125 return res
126
126
127 @classmethod
127 @classmethod
128 def getAll(cls):
128 def getAll(cls):
129 # deprecated and left for backward compatibility
129 # deprecated and left for backward compatibility
130 return cls.get_all()
130 return cls.get_all()
131
131
132 @classmethod
132 @classmethod
133 def get_all(cls):
133 def get_all(cls):
134 return cls.query().all()
134 return cls.query().all()
135
135
136 @classmethod
136 @classmethod
137 def delete(cls, id_):
137 def delete(cls, id_):
138 obj = cls.query().get(id_)
138 obj = cls.query().get(id_)
139 Session().delete(obj)
139 Session().delete(obj)
140
140
141 def __repr__(self):
141 def __repr__(self):
142 if hasattr(self, '__unicode__'):
142 if hasattr(self, '__unicode__'):
143 # python repr needs to return str
143 # python repr needs to return str
144 return safe_str(self.__unicode__())
144 return safe_str(self.__unicode__())
145 return '<DB:%s>' % (self.__class__.__name__)
145 return '<DB:%s>' % (self.__class__.__name__)
146
146
147
147
148 class RhodeCodeSetting(Base, BaseModel):
148 class RhodeCodeSetting(Base, BaseModel):
149 __tablename__ = 'rhodecode_settings'
149 __tablename__ = 'rhodecode_settings'
150 __table_args__ = (
150 __table_args__ = (
151 UniqueConstraint('app_settings_name'),
151 UniqueConstraint('app_settings_name'),
152 {'extend_existing': True, 'mysql_engine': 'InnoDB',
152 {'extend_existing': True, 'mysql_engine': 'InnoDB',
153 'mysql_charset': 'utf8'}
153 'mysql_charset': 'utf8'}
154 )
154 )
155 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
155 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
156 app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None)
156 app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None)
157 _app_settings_value = Column("app_settings_value", String(255), nullable=True, unique=None, default=None)
157 _app_settings_value = Column("app_settings_value", String(255), nullable=True, unique=None, default=None)
158
158
159 def __init__(self, k='', v=''):
159 def __init__(self, k='', v=''):
160 self.app_settings_name = k
160 self.app_settings_name = k
161 self.app_settings_value = v
161 self.app_settings_value = v
162
162
163 @validates('_app_settings_value')
163 @validates('_app_settings_value')
164 def validate_settings_value(self, key, val):
164 def validate_settings_value(self, key, val):
165 assert type(val) == unicode
165 assert type(val) == unicode
166 return val
166 return val
167
167
168 @hybrid_property
168 @hybrid_property
169 def app_settings_value(self):
169 def app_settings_value(self):
170 v = self._app_settings_value
170 v = self._app_settings_value
171 if self.app_settings_name in ["ldap_active",
171 if self.app_settings_name in ["ldap_active",
172 "default_repo_enable_statistics",
172 "default_repo_enable_statistics",
173 "default_repo_enable_locking",
173 "default_repo_enable_locking",
174 "default_repo_private",
174 "default_repo_private",
175 "default_repo_enable_downloads"]:
175 "default_repo_enable_downloads"]:
176 v = str2bool(v)
176 v = str2bool(v)
177 return v
177 return v
178
178
179 @app_settings_value.setter
179 @app_settings_value.setter
180 def app_settings_value(self, val):
180 def app_settings_value(self, val):
181 """
181 """
182 Setter that will always make sure we use unicode in app_settings_value
182 Setter that will always make sure we use unicode in app_settings_value
183
183
184 :param val:
184 :param val:
185 """
185 """
186 self._app_settings_value = safe_unicode(val)
186 self._app_settings_value = safe_unicode(val)
187
187
188 def __unicode__(self):
188 def __unicode__(self):
189 return u"<%s('%s:%s')>" % (
189 return u"<%s('%s:%s')>" % (
190 self.__class__.__name__,
190 self.__class__.__name__,
191 self.app_settings_name, self.app_settings_value
191 self.app_settings_name, self.app_settings_value
192 )
192 )
193
193
194
194
195 class RhodeCodeUi(Base, BaseModel):
195 class RhodeCodeUi(Base, BaseModel):
196 __tablename__ = 'rhodecode_ui'
196 __tablename__ = 'rhodecode_ui'
197 __table_args__ = (
197 __table_args__ = (
198 UniqueConstraint('ui_key'),
198 UniqueConstraint('ui_key'),
199 {'extend_existing': True, 'mysql_engine': 'InnoDB',
199 {'extend_existing': True, 'mysql_engine': 'InnoDB',
200 'mysql_charset': 'utf8'}
200 'mysql_charset': 'utf8'}
201 )
201 )
202
202
203 HOOK_REPO_SIZE = 'changegroup.repo_size'
203 HOOK_REPO_SIZE = 'changegroup.repo_size'
204 HOOK_PUSH = 'changegroup.push_logger'
204 HOOK_PUSH = 'changegroup.push_logger'
205 HOOK_PRE_PUSH = 'prechangegroup.pre_push'
205 HOOK_PRE_PUSH = 'prechangegroup.pre_push'
206 HOOK_PULL = 'outgoing.pull_logger'
206 HOOK_PULL = 'outgoing.pull_logger'
207 HOOK_PRE_PULL = 'preoutgoing.pre_pull'
207 HOOK_PRE_PULL = 'preoutgoing.pre_pull'
208
208
209 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
209 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
210 ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None)
210 ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None)
211 ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None)
211 ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None)
212 ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None)
212 ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None)
213 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
213 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
214
214
215
215
216
216
217 class User(Base, BaseModel):
217 class User(Base, BaseModel):
218 __tablename__ = 'users'
218 __tablename__ = 'users'
219 __table_args__ = (
219 __table_args__ = (
220 UniqueConstraint('username'), UniqueConstraint('email'),
220 UniqueConstraint('username'), UniqueConstraint('email'),
221 Index('u_username_idx', 'username'),
221 Index('u_username_idx', 'username'),
222 Index('u_email_idx', 'email'),
222 Index('u_email_idx', 'email'),
223 {'extend_existing': True, 'mysql_engine': 'InnoDB',
223 {'extend_existing': True, 'mysql_engine': 'InnoDB',
224 'mysql_charset': 'utf8'}
224 'mysql_charset': 'utf8'}
225 )
225 )
226 DEFAULT_USER = 'default'
226 DEFAULT_USER = 'default'
227 DEFAULT_PERMISSIONS = [
227 DEFAULT_PERMISSIONS = [
228 'hg.register.manual_activate', 'hg.create.repository',
228 'hg.register.manual_activate', 'hg.create.repository',
229 'hg.fork.repository', 'repository.read', 'group.read'
229 'hg.fork.repository', 'repository.read', 'group.read'
230 ]
230 ]
231 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
231 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
232 username = Column("username", String(255), nullable=True, unique=None, default=None)
232 username = Column("username", String(255), nullable=True, unique=None, default=None)
233 password = Column("password", String(255), nullable=True, unique=None, default=None)
233 password = Column("password", String(255), nullable=True, unique=None, default=None)
234 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
234 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
235 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
235 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
236 name = Column("firstname", String(255), nullable=True, unique=None, default=None)
236 name = Column("firstname", String(255), nullable=True, unique=None, default=None)
237 lastname = Column("lastname", String(255), nullable=True, unique=None, default=None)
237 lastname = Column("lastname", String(255), nullable=True, unique=None, default=None)
238 _email = Column("email", String(255), nullable=True, unique=None, default=None)
238 _email = Column("email", String(255), nullable=True, unique=None, default=None)
239 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
239 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
240 ldap_dn = Column("ldap_dn", String(255), nullable=True, unique=None, default=None)
240 ldap_dn = Column("ldap_dn", String(255), nullable=True, unique=None, default=None)
241 api_key = Column("api_key", String(255), nullable=True, unique=None, default=None)
241 api_key = Column("api_key", String(255), nullable=True, unique=None, default=None)
242 inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
242 inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
243
243
244 user_log = relationship('UserLog')
244 user_log = relationship('UserLog')
245 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
245 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
246
246
247 repositories = relationship('Repository')
247 repositories = relationship('Repository')
248 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
248 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
249 followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all')
249 followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all')
250
250
251 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
251 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
252 repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all')
252 repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all')
253
253
254 group_member = relationship('UserGroupMember', cascade='all')
254 group_member = relationship('UserGroupMember', cascade='all')
255
255
256 notifications = relationship('UserNotification', cascade='all')
256 notifications = relationship('UserNotification', cascade='all')
257 # notifications assigned to this user
257 # notifications assigned to this user
258 user_created_notifications = relationship('Notification', cascade='all')
258 user_created_notifications = relationship('Notification', cascade='all')
259 # comments created by this user
259 # comments created by this user
260 user_comments = relationship('ChangesetComment', cascade='all')
260 user_comments = relationship('ChangesetComment', cascade='all')
261 user_emails = relationship('UserEmailMap', cascade='all')
261 user_emails = relationship('UserEmailMap', cascade='all')
262
262
263 @hybrid_property
263 @hybrid_property
264 def email(self):
264 def email(self):
265 return self._email
265 return self._email
266
266
267 @email.setter
267 @email.setter
268 def email(self, val):
268 def email(self, val):
269 self._email = val.lower() if val else None
269 self._email = val.lower() if val else None
270
270
271 @property
271 @property
272 def firstname(self):
272 def firstname(self):
273 # alias for future
273 # alias for future
274 return self.name
274 return self.name
275
275
276 @property
276 @property
277 def username_and_name(self):
277 def username_and_name(self):
278 return '%s (%s %s)' % (self.username, self.firstname, self.lastname)
278 return '%s (%s %s)' % (self.username, self.firstname, self.lastname)
279
279
280 @property
280 @property
281 def full_name(self):
281 def full_name(self):
282 return '%s %s' % (self.firstname, self.lastname)
282 return '%s %s' % (self.firstname, self.lastname)
283
283
284 @property
284 @property
285 def full_contact(self):
285 def full_contact(self):
286 return '%s %s <%s>' % (self.firstname, self.lastname, self.email)
286 return '%s %s <%s>' % (self.firstname, self.lastname, self.email)
287
287
288 @property
288 @property
289 def short_contact(self):
289 def short_contact(self):
290 return '%s %s' % (self.firstname, self.lastname)
290 return '%s %s' % (self.firstname, self.lastname)
291
291
292 @property
292 @property
293 def is_admin(self):
293 def is_admin(self):
294 return self.admin
294 return self.admin
295
295
296 @classmethod
296 @classmethod
297 def get_by_username(cls, username, case_insensitive=False, cache=False):
297 def get_by_username(cls, username, case_insensitive=False, cache=False):
298 if case_insensitive:
298 if case_insensitive:
299 q = cls.query().filter(cls.username.ilike(username))
299 q = cls.query().filter(cls.username.ilike(username))
300 else:
300 else:
301 q = cls.query().filter(cls.username == username)
301 q = cls.query().filter(cls.username == username)
302
302
303 if cache:
303 if cache:
304 q = q.options(FromCache(
304 q = q.options(FromCache(
305 "sql_cache_short",
305 "sql_cache_short",
306 "get_user_%s" % _hash_key(username)
306 "get_user_%s" % _hash_key(username)
307 )
307 )
308 )
308 )
309 return q.scalar()
309 return q.scalar()
310
310
311 @classmethod
311 @classmethod
312 def get_by_auth_token(cls, auth_token, cache=False):
312 def get_by_auth_token(cls, auth_token, cache=False):
313 q = cls.query().filter(cls.api_key == auth_token)
313 q = cls.query().filter(cls.api_key == auth_token)
314
314
315 if cache:
315 if cache:
316 q = q.options(FromCache("sql_cache_short",
316 q = q.options(FromCache("sql_cache_short",
317 "get_auth_token_%s" % auth_token))
317 "get_auth_token_%s" % auth_token))
318 return q.scalar()
318 return q.scalar()
319
319
320 @classmethod
320 @classmethod
321 def get_by_email(cls, email, case_insensitive=False, cache=False):
321 def get_by_email(cls, email, case_insensitive=False, cache=False):
322 if case_insensitive:
322 if case_insensitive:
323 q = cls.query().filter(cls.email.ilike(email))
323 q = cls.query().filter(cls.email.ilike(email))
324 else:
324 else:
325 q = cls.query().filter(cls.email == email)
325 q = cls.query().filter(cls.email == email)
326
326
327 if cache:
327 if cache:
328 q = q.options(FromCache("sql_cache_short",
328 q = q.options(FromCache("sql_cache_short",
329 "get_email_key_%s" % email))
329 "get_email_key_%s" % email))
330
330
331 ret = q.scalar()
331 ret = q.scalar()
332 if ret is None:
332 if ret is None:
333 q = UserEmailMap.query()
333 q = UserEmailMap.query()
334 # try fetching in alternate email map
334 # try fetching in alternate email map
335 if case_insensitive:
335 if case_insensitive:
336 q = q.filter(UserEmailMap.email.ilike(email))
336 q = q.filter(UserEmailMap.email.ilike(email))
337 else:
337 else:
338 q = q.filter(UserEmailMap.email == email)
338 q = q.filter(UserEmailMap.email == email)
339 q = q.options(joinedload(UserEmailMap.user))
339 q = q.options(joinedload(UserEmailMap.user))
340 if cache:
340 if cache:
341 q = q.options(FromCache("sql_cache_short",
341 q = q.options(FromCache("sql_cache_short",
342 "get_email_map_key_%s" % email))
342 "get_email_map_key_%s" % email))
343 ret = getattr(q.scalar(), 'user', None)
343 ret = getattr(q.scalar(), 'user', None)
344
344
345 return ret
345 return ret
346
346
347
347
348 class UserEmailMap(Base, BaseModel):
348 class UserEmailMap(Base, BaseModel):
349 __tablename__ = 'user_email_map'
349 __tablename__ = 'user_email_map'
350 __table_args__ = (
350 __table_args__ = (
351 Index('uem_email_idx', 'email'),
351 Index('uem_email_idx', 'email'),
352 UniqueConstraint('email'),
352 UniqueConstraint('email'),
353 {'extend_existing': True, 'mysql_engine': 'InnoDB',
353 {'extend_existing': True, 'mysql_engine': 'InnoDB',
354 'mysql_charset': 'utf8'}
354 'mysql_charset': 'utf8'}
355 )
355 )
356 __mapper_args__ = {}
356 __mapper_args__ = {}
357
357
358 email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
358 email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
359 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
359 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
360 _email = Column("email", String(255), nullable=True, unique=False, default=None)
360 _email = Column("email", String(255), nullable=True, unique=False, default=None)
361 user = relationship('User', lazy='joined')
361 user = relationship('User', lazy='joined')
362
362
363 @validates('_email')
363 @validates('_email')
364 def validate_email(self, key, email):
364 def validate_email(self, key, email):
365 # check if this email is not main one
365 # check if this email is not main one
366 main_email = Session().query(User).filter(User.email == email).scalar()
366 main_email = Session().query(User).filter(User.email == email).scalar()
367 if main_email is not None:
367 if main_email is not None:
368 raise AttributeError('email %s is present is user table' % email)
368 raise AttributeError('email %s is present is user table' % email)
369 return email
369 return email
370
370
371 @hybrid_property
371 @hybrid_property
372 def email(self):
372 def email(self):
373 return self._email
373 return self._email
374
374
375 @email.setter
375 @email.setter
376 def email(self, val):
376 def email(self, val):
377 self._email = val.lower() if val else None
377 self._email = val.lower() if val else None
378
378
379
379
380 class UserIpMap(Base, BaseModel):
380 class UserIpMap(Base, BaseModel):
381 __tablename__ = 'user_ip_map'
381 __tablename__ = 'user_ip_map'
382 __table_args__ = (
382 __table_args__ = (
383 UniqueConstraint('user_id', 'ip_addr'),
383 UniqueConstraint('user_id', 'ip_addr'),
384 {'extend_existing': True, 'mysql_engine': 'InnoDB',
384 {'extend_existing': True, 'mysql_engine': 'InnoDB',
385 'mysql_charset': 'utf8'}
385 'mysql_charset': 'utf8'}
386 )
386 )
387 __mapper_args__ = {}
387 __mapper_args__ = {}
388
388
389 ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
389 ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
390 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
390 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
391 ip_addr = Column("ip_addr", String(255), nullable=True, unique=False, default=None)
391 ip_addr = Column("ip_addr", String(255), nullable=True, unique=False, default=None)
392 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
392 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
393 user = relationship('User', lazy='joined')
393 user = relationship('User', lazy='joined')
394
394
395
395
396 class UserLog(Base, BaseModel):
396 class UserLog(Base, BaseModel):
397 __tablename__ = 'user_logs'
397 __tablename__ = 'user_logs'
398 __table_args__ = (
398 __table_args__ = (
399 {'extend_existing': True, 'mysql_engine': 'InnoDB',
399 {'extend_existing': True, 'mysql_engine': 'InnoDB',
400 'mysql_charset': 'utf8'},
400 'mysql_charset': 'utf8'},
401 )
401 )
402 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
402 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
403 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
403 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
404 username = Column("username", String(255), nullable=True, unique=None, default=None)
404 username = Column("username", String(255), nullable=True, unique=None, default=None)
405 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
405 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
406 repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None)
406 repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None)
407 user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None)
407 user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None)
408 action = Column("action", String(1200000), nullable=True, unique=None, default=None)
408 action = Column("action", String(1200000), nullable=True, unique=None, default=None)
409 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
409 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
410
410
411
411
412 user = relationship('User')
412 user = relationship('User')
413 repository = relationship('Repository', cascade='')
413 repository = relationship('Repository', cascade='')
414
414
415
415
416 class UserGroup(Base, BaseModel):
416 class UserGroup(Base, BaseModel):
417 __tablename__ = 'users_groups'
417 __tablename__ = 'users_groups'
418 __table_args__ = (
418 __table_args__ = (
419 {'extend_existing': True, 'mysql_engine': 'InnoDB',
419 {'extend_existing': True, 'mysql_engine': 'InnoDB',
420 'mysql_charset': 'utf8'},
420 'mysql_charset': 'utf8'},
421 )
421 )
422
422
423 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
423 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
424 users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None)
424 users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None)
425 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
425 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
426 inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
426 inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
427
427
428 members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
428 members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
429 users_group_to_perm = relationship('UserGroupToPerm', cascade='all')
429 users_group_to_perm = relationship('UserGroupToPerm', cascade='all')
430 users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
430 users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
431
431
432 def __unicode__(self):
432 def __unicode__(self):
433 return u'<userGroup(%s)>' % (self.users_group_name)
433 return u'<userGroup(%s)>' % (self.users_group_name)
434
434
435 @classmethod
435 @classmethod
436 def get_by_group_name(cls, group_name, cache=False,
436 def get_by_group_name(cls, group_name, cache=False,
437 case_insensitive=False):
437 case_insensitive=False):
438 if case_insensitive:
438 if case_insensitive:
439 q = cls.query().filter(cls.users_group_name.ilike(group_name))
439 q = cls.query().filter(cls.users_group_name.ilike(group_name))
440 else:
440 else:
441 q = cls.query().filter(cls.users_group_name == group_name)
441 q = cls.query().filter(cls.users_group_name == group_name)
442 if cache:
442 if cache:
443 q = q.options(FromCache(
443 q = q.options(FromCache(
444 "sql_cache_short",
444 "sql_cache_short",
445 "get_user_%s" % _hash_key(group_name)
445 "get_user_%s" % _hash_key(group_name)
446 )
446 )
447 )
447 )
448 return q.scalar()
448 return q.scalar()
449
449
450 @classmethod
450 @classmethod
451 def get(cls, users_group_id, cache=False):
451 def get(cls, users_group_id, cache=False):
452 user_group = cls.query()
452 user_group = cls.query()
453 if cache:
453 if cache:
454 user_group = user_group.options(FromCache("sql_cache_short",
454 user_group = user_group.options(FromCache("sql_cache_short",
455 "get_users_group_%s" % users_group_id))
455 "get_users_group_%s" % users_group_id))
456 return user_group.get(users_group_id)
456 return user_group.get(users_group_id)
457
457
458
458
459 class UserGroupMember(Base, BaseModel):
459 class UserGroupMember(Base, BaseModel):
460 __tablename__ = 'users_groups_members'
460 __tablename__ = 'users_groups_members'
461 __table_args__ = (
461 __table_args__ = (
462 {'extend_existing': True, 'mysql_engine': 'InnoDB',
462 {'extend_existing': True, 'mysql_engine': 'InnoDB',
463 'mysql_charset': 'utf8'},
463 'mysql_charset': 'utf8'},
464 )
464 )
465
465
466 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
466 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
467 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
467 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
468 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
468 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
469
469
470 user = relationship('User', lazy='joined')
470 user = relationship('User', lazy='joined')
471 users_group = relationship('UserGroup')
471 users_group = relationship('UserGroup')
472
472
473 def __init__(self, gr_id='', u_id=''):
473 def __init__(self, gr_id='', u_id=''):
474 self.users_group_id = gr_id
474 self.users_group_id = gr_id
475 self.user_id = u_id
475 self.user_id = u_id
476
476
477
477
478 class Repository(Base, BaseModel):
478 class Repository(Base, BaseModel):
479 __tablename__ = 'repositories'
479 __tablename__ = 'repositories'
480 __table_args__ = (
480 __table_args__ = (
481 UniqueConstraint('repo_name'),
481 UniqueConstraint('repo_name'),
482 Index('r_repo_name_idx', 'repo_name'),
482 Index('r_repo_name_idx', 'repo_name'),
483 {'extend_existing': True, 'mysql_engine': 'InnoDB',
483 {'extend_existing': True, 'mysql_engine': 'InnoDB',
484 'mysql_charset': 'utf8'},
484 'mysql_charset': 'utf8'},
485 )
485 )
486
486
487 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
487 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
488 repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None)
488 repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None)
489 clone_uri = Column("clone_uri", String(255), nullable=True, unique=False, default=None)
489 clone_uri = Column("clone_uri", String(255), nullable=True, unique=False, default=None)
490 repo_type = Column("repo_type", String(255), nullable=False, unique=False, default=None)
490 repo_type = Column("repo_type", String(255), nullable=False, unique=False, default=None)
491 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
491 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
492 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
492 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
493 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
493 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
494 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
494 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
495 description = Column("description", String(10000), nullable=True, unique=None, default=None)
495 description = Column("description", String(10000), nullable=True, unique=None, default=None)
496 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
496 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
497 updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
497 updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
498 landing_rev = Column("landing_revision", String(255), nullable=False, unique=False, default=None)
498 landing_rev = Column("landing_revision", String(255), nullable=False, unique=False, default=None)
499 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
499 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
500 _locked = Column("locked", String(255), nullable=True, unique=False, default=None)
500 _locked = Column("locked", String(255), nullable=True, unique=False, default=None)
501 _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) #JSON data
501 _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) #JSON data
502
502
503 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
503 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
504 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
504 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
505
505
506 user = relationship('User')
506 user = relationship('User')
507 fork = relationship('Repository', remote_side=repo_id)
507 fork = relationship('Repository', remote_side=repo_id)
508 group = relationship('RepoGroup')
508 group = relationship('RepoGroup')
509 repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
509 repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
510 users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
510 users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
511 stats = relationship('Statistics', cascade='all', uselist=False)
511 stats = relationship('Statistics', cascade='all', uselist=False)
512
512
513 followers = relationship('UserFollowing',
513 followers = relationship('UserFollowing',
514 primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id',
514 primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id',
515 cascade='all')
515 cascade='all')
516
516
517 logs = relationship('UserLog')
517 logs = relationship('UserLog')
518 comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan")
518 comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan")
519
519
520 pull_requests_org = relationship('PullRequest',
520 pull_requests_org = relationship('PullRequest',
521 primaryjoin='PullRequest.org_repo_id==Repository.repo_id',
521 primaryjoin='PullRequest.org_repo_id==Repository.repo_id',
522 cascade="all, delete, delete-orphan")
522 cascade="all, delete, delete-orphan")
523
523
524 pull_requests_other = relationship('PullRequest',
524 pull_requests_other = relationship('PullRequest',
525 primaryjoin='PullRequest.other_repo_id==Repository.repo_id',
525 primaryjoin='PullRequest.other_repo_id==Repository.repo_id',
526 cascade="all, delete, delete-orphan")
526 cascade="all, delete, delete-orphan")
527
527
528 def __unicode__(self):
528 def __unicode__(self):
529 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id,
529 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id,
530 safe_unicode(self.repo_name))
530 safe_unicode(self.repo_name))
531
531
532
532
533 @classmethod
533 @classmethod
534 def get_by_repo_name(cls, repo_name):
534 def get_by_repo_name(cls, repo_name):
535 q = Session().query(cls).filter(cls.repo_name == repo_name)
535 q = Session().query(cls).filter(cls.repo_name == repo_name)
536 q = q.options(joinedload(Repository.fork))\
536 q = q.options(joinedload(Repository.fork))\
537 .options(joinedload(Repository.user))\
537 .options(joinedload(Repository.user))\
538 .options(joinedload(Repository.group))
538 .options(joinedload(Repository.group))
539 return q.scalar()
539 return q.scalar()
540
540
541
541
542 class RepoGroup(Base, BaseModel):
542 class RepoGroup(Base, BaseModel):
543 __tablename__ = 'groups'
543 __tablename__ = 'groups'
544 __table_args__ = (
544 __table_args__ = (
545 UniqueConstraint('group_name', 'group_parent_id'),
545 UniqueConstraint('group_name', 'group_parent_id'),
546 CheckConstraint('group_id != group_parent_id'),
547 {'extend_existing': True, 'mysql_engine': 'InnoDB',
546 {'extend_existing': True, 'mysql_engine': 'InnoDB',
548 'mysql_charset': 'utf8'},
547 'mysql_charset': 'utf8'},
549 )
548 )
550 __mapper_args__ = {'order_by': 'group_name'}
549 __mapper_args__ = {'order_by': 'group_name'}
551
550
552 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
551 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
553 group_name = Column("group_name", String(255), nullable=False, unique=True, default=None)
552 group_name = Column("group_name", String(255), nullable=False, unique=True, default=None)
554 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
553 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
555 group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None)
554 group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None)
556 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
555 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
557
556
558 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
557 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
559 users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
558 users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
560 parent_group = relationship('RepoGroup', remote_side=group_id)
559 parent_group = relationship('RepoGroup', remote_side=group_id)
561
560
562 def __init__(self, group_name='', parent_group=None):
561 def __init__(self, group_name='', parent_group=None):
563 self.group_name = group_name
562 self.group_name = group_name
564 self.parent_group = parent_group
563 self.parent_group = parent_group
565
564
566 def __unicode__(self):
565 def __unicode__(self):
567 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
566 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
568 self.group_name)
567 self.group_name)
569
568
570 @classmethod
569 @classmethod
571 def url_sep(cls):
570 def url_sep(cls):
572 return URL_SEP
571 return URL_SEP
573
572
574 @classmethod
573 @classmethod
575 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
574 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
576 if case_insensitive:
575 if case_insensitive:
577 gr = cls.query()\
576 gr = cls.query()\
578 .filter(cls.group_name.ilike(group_name))
577 .filter(cls.group_name.ilike(group_name))
579 else:
578 else:
580 gr = cls.query()\
579 gr = cls.query()\
581 .filter(cls.group_name == group_name)
580 .filter(cls.group_name == group_name)
582 if cache:
581 if cache:
583 gr = gr.options(FromCache(
582 gr = gr.options(FromCache(
584 "sql_cache_short",
583 "sql_cache_short",
585 "get_group_%s" % _hash_key(group_name)
584 "get_group_%s" % _hash_key(group_name)
586 )
585 )
587 )
586 )
588 return gr.scalar()
587 return gr.scalar()
589
588
590
589
591 class Permission(Base, BaseModel):
590 class Permission(Base, BaseModel):
592 __tablename__ = 'permissions'
591 __tablename__ = 'permissions'
593 __table_args__ = (
592 __table_args__ = (
594 Index('p_perm_name_idx', 'permission_name'),
593 Index('p_perm_name_idx', 'permission_name'),
595 {'extend_existing': True, 'mysql_engine': 'InnoDB',
594 {'extend_existing': True, 'mysql_engine': 'InnoDB',
596 'mysql_charset': 'utf8'},
595 'mysql_charset': 'utf8'},
597 )
596 )
598 PERMS = [
597 PERMS = [
599 ('repository.none', _('Repository no access')),
598 ('repository.none', _('Repository no access')),
600 ('repository.read', _('Repository read access')),
599 ('repository.read', _('Repository read access')),
601 ('repository.write', _('Repository write access')),
600 ('repository.write', _('Repository write access')),
602 ('repository.admin', _('Repository admin access')),
601 ('repository.admin', _('Repository admin access')),
603
602
604 ('group.none', _('Repositories Group no access')),
603 ('group.none', _('Repositories Group no access')),
605 ('group.read', _('Repositories Group read access')),
604 ('group.read', _('Repositories Group read access')),
606 ('group.write', _('Repositories Group write access')),
605 ('group.write', _('Repositories Group write access')),
607 ('group.admin', _('Repositories Group admin access')),
606 ('group.admin', _('Repositories Group admin access')),
608
607
609 ('hg.admin', _('RhodeCode Administrator')),
608 ('hg.admin', _('RhodeCode Administrator')),
610 ('hg.create.none', _('Repository creation disabled')),
609 ('hg.create.none', _('Repository creation disabled')),
611 ('hg.create.repository', _('Repository creation enabled')),
610 ('hg.create.repository', _('Repository creation enabled')),
612 ('hg.fork.none', _('Repository forking disabled')),
611 ('hg.fork.none', _('Repository forking disabled')),
613 ('hg.fork.repository', _('Repository forking enabled')),
612 ('hg.fork.repository', _('Repository forking enabled')),
614 ('hg.register.none', _('Register disabled')),
613 ('hg.register.none', _('Register disabled')),
615 ('hg.register.manual_activate', _('Register new user with RhodeCode '
614 ('hg.register.manual_activate', _('Register new user with RhodeCode '
616 'with manual activation')),
615 'with manual activation')),
617
616
618 ('hg.register.auto_activate', _('Register new user with RhodeCode '
617 ('hg.register.auto_activate', _('Register new user with RhodeCode '
619 'with auto activation')),
618 'with auto activation')),
620 ]
619 ]
621
620
622 # defines which permissions are more important higher the more important
621 # defines which permissions are more important higher the more important
623 PERM_WEIGHTS = {
622 PERM_WEIGHTS = {
624 'repository.none': 0,
623 'repository.none': 0,
625 'repository.read': 1,
624 'repository.read': 1,
626 'repository.write': 3,
625 'repository.write': 3,
627 'repository.admin': 4,
626 'repository.admin': 4,
628
627
629 'group.none': 0,
628 'group.none': 0,
630 'group.read': 1,
629 'group.read': 1,
631 'group.write': 3,
630 'group.write': 3,
632 'group.admin': 4,
631 'group.admin': 4,
633
632
634 'hg.fork.none': 0,
633 'hg.fork.none': 0,
635 'hg.fork.repository': 1,
634 'hg.fork.repository': 1,
636 'hg.create.none': 0,
635 'hg.create.none': 0,
637 'hg.create.repository':1
636 'hg.create.repository':1
638 }
637 }
639
638
640 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
639 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
641 permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None)
640 permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None)
642 permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None)
641 permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None)
643
642
644 def __unicode__(self):
643 def __unicode__(self):
645 return u"<%s('%s:%s')>" % (
644 return u"<%s('%s:%s')>" % (
646 self.__class__.__name__, self.permission_id, self.permission_name
645 self.__class__.__name__, self.permission_id, self.permission_name
647 )
646 )
648
647
649 @classmethod
648 @classmethod
650 def get_by_key(cls, key):
649 def get_by_key(cls, key):
651 return cls.query().filter(cls.permission_name == key).scalar()
650 return cls.query().filter(cls.permission_name == key).scalar()
652
651
653
652
654 class UserRepoToPerm(Base, BaseModel):
653 class UserRepoToPerm(Base, BaseModel):
655 __tablename__ = 'repo_to_perm'
654 __tablename__ = 'repo_to_perm'
656 __table_args__ = (
655 __table_args__ = (
657 UniqueConstraint('user_id', 'repository_id', 'permission_id'),
656 UniqueConstraint('user_id', 'repository_id', 'permission_id'),
658 {'extend_existing': True, 'mysql_engine': 'InnoDB',
657 {'extend_existing': True, 'mysql_engine': 'InnoDB',
659 'mysql_charset': 'utf8'}
658 'mysql_charset': 'utf8'}
660 )
659 )
661 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
660 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
662 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
661 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
663 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
662 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
664 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
663 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
665
664
666 user = relationship('User')
665 user = relationship('User')
667 repository = relationship('Repository')
666 repository = relationship('Repository')
668 permission = relationship('Permission')
667 permission = relationship('Permission')
669
668
670 def __unicode__(self):
669 def __unicode__(self):
671 return u'<user:%s => %s >' % (self.user, self.repository)
670 return u'<user:%s => %s >' % (self.user, self.repository)
672
671
673
672
674 class UserToPerm(Base, BaseModel):
673 class UserToPerm(Base, BaseModel):
675 __tablename__ = 'user_to_perm'
674 __tablename__ = 'user_to_perm'
676 __table_args__ = (
675 __table_args__ = (
677 UniqueConstraint('user_id', 'permission_id'),
676 UniqueConstraint('user_id', 'permission_id'),
678 {'extend_existing': True, 'mysql_engine': 'InnoDB',
677 {'extend_existing': True, 'mysql_engine': 'InnoDB',
679 'mysql_charset': 'utf8'}
678 'mysql_charset': 'utf8'}
680 )
679 )
681 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
680 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
682 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
681 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
683 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
682 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
684
683
685 user = relationship('User')
684 user = relationship('User')
686 permission = relationship('Permission', lazy='joined')
685 permission = relationship('Permission', lazy='joined')
687
686
688
687
689 class UserGroupRepoToPerm(Base, BaseModel):
688 class UserGroupRepoToPerm(Base, BaseModel):
690 __tablename__ = 'users_group_repo_to_perm'
689 __tablename__ = 'users_group_repo_to_perm'
691 __table_args__ = (
690 __table_args__ = (
692 UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
691 UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
693 {'extend_existing': True, 'mysql_engine': 'InnoDB',
692 {'extend_existing': True, 'mysql_engine': 'InnoDB',
694 'mysql_charset': 'utf8'}
693 'mysql_charset': 'utf8'}
695 )
694 )
696 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
695 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
697 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
696 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
698 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
697 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
699 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
698 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
700
699
701 users_group = relationship('UserGroup')
700 users_group = relationship('UserGroup')
702 permission = relationship('Permission')
701 permission = relationship('Permission')
703 repository = relationship('Repository')
702 repository = relationship('Repository')
704
703
705 def __unicode__(self):
704 def __unicode__(self):
706 return u'<userGroup:%s => %s >' % (self.users_group, self.repository)
705 return u'<userGroup:%s => %s >' % (self.users_group, self.repository)
707
706
708
707
709 class UserGroupToPerm(Base, BaseModel):
708 class UserGroupToPerm(Base, BaseModel):
710 __tablename__ = 'users_group_to_perm'
709 __tablename__ = 'users_group_to_perm'
711 __table_args__ = (
710 __table_args__ = (
712 UniqueConstraint('users_group_id', 'permission_id',),
711 UniqueConstraint('users_group_id', 'permission_id',),
713 {'extend_existing': True, 'mysql_engine': 'InnoDB',
712 {'extend_existing': True, 'mysql_engine': 'InnoDB',
714 'mysql_charset': 'utf8'}
713 'mysql_charset': 'utf8'}
715 )
714 )
716 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
715 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
717 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
716 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
718 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
717 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
719
718
720 users_group = relationship('UserGroup')
719 users_group = relationship('UserGroup')
721 permission = relationship('Permission')
720 permission = relationship('Permission')
722
721
723
722
724 class UserRepoGroupToPerm(Base, BaseModel):
723 class UserRepoGroupToPerm(Base, BaseModel):
725 __tablename__ = 'user_repo_group_to_perm'
724 __tablename__ = 'user_repo_group_to_perm'
726 __table_args__ = (
725 __table_args__ = (
727 UniqueConstraint('user_id', 'group_id', 'permission_id'),
726 UniqueConstraint('user_id', 'group_id', 'permission_id'),
728 {'extend_existing': True, 'mysql_engine': 'InnoDB',
727 {'extend_existing': True, 'mysql_engine': 'InnoDB',
729 'mysql_charset': 'utf8'}
728 'mysql_charset': 'utf8'}
730 )
729 )
731
730
732 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
731 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
733 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
732 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
734 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
733 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
735 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
734 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
736
735
737 user = relationship('User')
736 user = relationship('User')
738 group = relationship('RepoGroup')
737 group = relationship('RepoGroup')
739 permission = relationship('Permission')
738 permission = relationship('Permission')
740
739
741
740
742 class UserGroupRepoGroupToPerm(Base, BaseModel):
741 class UserGroupRepoGroupToPerm(Base, BaseModel):
743 __tablename__ = 'users_group_repo_group_to_perm'
742 __tablename__ = 'users_group_repo_group_to_perm'
744 __table_args__ = (
743 __table_args__ = (
745 UniqueConstraint('users_group_id', 'group_id'),
744 UniqueConstraint('users_group_id', 'group_id'),
746 {'extend_existing': True, 'mysql_engine': 'InnoDB',
745 {'extend_existing': True, 'mysql_engine': 'InnoDB',
747 'mysql_charset': 'utf8'}
746 'mysql_charset': 'utf8'}
748 )
747 )
749
748
750 users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
749 users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
751 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
750 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
752 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
751 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
753 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
752 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
754
753
755 users_group = relationship('UserGroup')
754 users_group = relationship('UserGroup')
756 permission = relationship('Permission')
755 permission = relationship('Permission')
757 group = relationship('RepoGroup')
756 group = relationship('RepoGroup')
758
757
759
758
760 class Statistics(Base, BaseModel):
759 class Statistics(Base, BaseModel):
761 __tablename__ = 'statistics'
760 __tablename__ = 'statistics'
762 __table_args__ = (
761 __table_args__ = (
763 UniqueConstraint('repository_id'),
762 UniqueConstraint('repository_id'),
764 {'extend_existing': True, 'mysql_engine': 'InnoDB',
763 {'extend_existing': True, 'mysql_engine': 'InnoDB',
765 'mysql_charset': 'utf8'}
764 'mysql_charset': 'utf8'}
766 )
765 )
767 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
766 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
768 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
767 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
769 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
768 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
770 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
769 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
771 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
770 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
772 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
771 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
773
772
774 repository = relationship('Repository', single_parent=True)
773 repository = relationship('Repository', single_parent=True)
775
774
776
775
777 class UserFollowing(Base, BaseModel):
776 class UserFollowing(Base, BaseModel):
778 __tablename__ = 'user_followings'
777 __tablename__ = 'user_followings'
779 __table_args__ = (
778 __table_args__ = (
780 UniqueConstraint('user_id', 'follows_repository_id'),
779 UniqueConstraint('user_id', 'follows_repository_id'),
781 UniqueConstraint('user_id', 'follows_user_id'),
780 UniqueConstraint('user_id', 'follows_user_id'),
782 {'extend_existing': True, 'mysql_engine': 'InnoDB',
781 {'extend_existing': True, 'mysql_engine': 'InnoDB',
783 'mysql_charset': 'utf8'}
782 'mysql_charset': 'utf8'}
784 )
783 )
785
784
786 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
785 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
787 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
786 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
788 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
787 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
789 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
788 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
790 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
789 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
791
790
792 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
791 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
793
792
794 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
793 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
795 follows_repository = relationship('Repository', order_by='Repository.repo_name')
794 follows_repository = relationship('Repository', order_by='Repository.repo_name')
796
795
797
796
798 class CacheInvalidation(Base, BaseModel):
797 class CacheInvalidation(Base, BaseModel):
799 __tablename__ = 'cache_invalidation'
798 __tablename__ = 'cache_invalidation'
800 __table_args__ = (
799 __table_args__ = (
801 UniqueConstraint('cache_key'),
800 UniqueConstraint('cache_key'),
802 Index('key_idx', 'cache_key'),
801 Index('key_idx', 'cache_key'),
803 {'extend_existing': True, 'mysql_engine': 'InnoDB',
802 {'extend_existing': True, 'mysql_engine': 'InnoDB',
804 'mysql_charset': 'utf8'},
803 'mysql_charset': 'utf8'},
805 )
804 )
806 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
805 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
807 cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None)
806 cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None)
808 cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None)
807 cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None)
809 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
808 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
810
809
811 def __init__(self, cache_key, cache_args=''):
810 def __init__(self, cache_key, cache_args=''):
812 self.cache_key = cache_key
811 self.cache_key = cache_key
813 self.cache_args = cache_args
812 self.cache_args = cache_args
814 self.cache_active = False
813 self.cache_active = False
815
814
816
815
817 class ChangesetComment(Base, BaseModel):
816 class ChangesetComment(Base, BaseModel):
818 __tablename__ = 'changeset_comments'
817 __tablename__ = 'changeset_comments'
819 __table_args__ = (
818 __table_args__ = (
820 Index('cc_revision_idx', 'revision'),
819 Index('cc_revision_idx', 'revision'),
821 {'extend_existing': True, 'mysql_engine': 'InnoDB',
820 {'extend_existing': True, 'mysql_engine': 'InnoDB',
822 'mysql_charset': 'utf8'},
821 'mysql_charset': 'utf8'},
823 )
822 )
824 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
823 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
825 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
824 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
826 revision = Column('revision', String(40), nullable=True)
825 revision = Column('revision', String(40), nullable=True)
827 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
826 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
828 line_no = Column('line_no', Unicode(10), nullable=True)
827 line_no = Column('line_no', Unicode(10), nullable=True)
829 hl_lines = Column('hl_lines', Unicode(512), nullable=True)
828 hl_lines = Column('hl_lines', Unicode(512), nullable=True)
830 f_path = Column('f_path', Unicode(1000), nullable=True)
829 f_path = Column('f_path', Unicode(1000), nullable=True)
831 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
830 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
832 text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False)
831 text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False)
833 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
832 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
834 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
833 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
835
834
836 author = relationship('User', lazy='joined')
835 author = relationship('User', lazy='joined')
837 repo = relationship('Repository')
836 repo = relationship('Repository')
838 status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan")
837 status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan")
839 pull_request = relationship('PullRequest', lazy='joined')
838 pull_request = relationship('PullRequest', lazy='joined')
840
839
841 @classmethod
840 @classmethod
842 def get_users(cls, revision=None, pull_request_id=None):
841 def get_users(cls, revision=None, pull_request_id=None):
843 """
842 """
844 Returns user associated with this ChangesetComment. ie those
843 Returns user associated with this ChangesetComment. ie those
845 who actually commented
844 who actually commented
846
845
847 :param cls:
846 :param cls:
848 :param revision:
847 :param revision:
849 """
848 """
850 q = Session().query(User)\
849 q = Session().query(User)\
851 .join(ChangesetComment.author)
850 .join(ChangesetComment.author)
852 if revision:
851 if revision:
853 q = q.filter(cls.revision == revision)
852 q = q.filter(cls.revision == revision)
854 elif pull_request_id:
853 elif pull_request_id:
855 q = q.filter(cls.pull_request_id == pull_request_id)
854 q = q.filter(cls.pull_request_id == pull_request_id)
856 return q.all()
855 return q.all()
857
856
858
857
859 class ChangesetStatus(Base, BaseModel):
858 class ChangesetStatus(Base, BaseModel):
860 __tablename__ = 'changeset_statuses'
859 __tablename__ = 'changeset_statuses'
861 __table_args__ = (
860 __table_args__ = (
862 Index('cs_revision_idx', 'revision'),
861 Index('cs_revision_idx', 'revision'),
863 Index('cs_version_idx', 'version'),
862 Index('cs_version_idx', 'version'),
864 UniqueConstraint('repo_id', 'revision', 'version'),
863 UniqueConstraint('repo_id', 'revision', 'version'),
865 {'extend_existing': True, 'mysql_engine': 'InnoDB',
864 {'extend_existing': True, 'mysql_engine': 'InnoDB',
866 'mysql_charset': 'utf8'}
865 'mysql_charset': 'utf8'}
867 )
866 )
868 STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed'
867 STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed'
869 STATUS_APPROVED = 'approved'
868 STATUS_APPROVED = 'approved'
870 STATUS_REJECTED = 'rejected'
869 STATUS_REJECTED = 'rejected'
871 STATUS_UNDER_REVIEW = 'under_review'
870 STATUS_UNDER_REVIEW = 'under_review'
872
871
873 STATUSES = [
872 STATUSES = [
874 (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default
873 (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default
875 (STATUS_APPROVED, _("Approved")),
874 (STATUS_APPROVED, _("Approved")),
876 (STATUS_REJECTED, _("Rejected")),
875 (STATUS_REJECTED, _("Rejected")),
877 (STATUS_UNDER_REVIEW, _("Under Review")),
876 (STATUS_UNDER_REVIEW, _("Under Review")),
878 ]
877 ]
879
878
880 changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True)
879 changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True)
881 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
880 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
882 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
881 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
883 revision = Column('revision', String(40), nullable=False)
882 revision = Column('revision', String(40), nullable=False)
884 status = Column('status', String(128), nullable=False, default=DEFAULT)
883 status = Column('status', String(128), nullable=False, default=DEFAULT)
885 changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id'))
884 changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id'))
886 modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
885 modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
887 version = Column('version', Integer(), nullable=False, default=0)
886 version = Column('version', Integer(), nullable=False, default=0)
888 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
887 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
889
888
890 author = relationship('User', lazy='joined')
889 author = relationship('User', lazy='joined')
891 repo = relationship('Repository')
890 repo = relationship('Repository')
892 comment = relationship('ChangesetComment', lazy='joined')
891 comment = relationship('ChangesetComment', lazy='joined')
893 pull_request = relationship('PullRequest', lazy='joined')
892 pull_request = relationship('PullRequest', lazy='joined')
894
893
895
894
896
895
897 class PullRequest(Base, BaseModel):
896 class PullRequest(Base, BaseModel):
898 __tablename__ = 'pull_requests'
897 __tablename__ = 'pull_requests'
899 __table_args__ = (
898 __table_args__ = (
900 {'extend_existing': True, 'mysql_engine': 'InnoDB',
899 {'extend_existing': True, 'mysql_engine': 'InnoDB',
901 'mysql_charset': 'utf8'},
900 'mysql_charset': 'utf8'},
902 )
901 )
903
902
904 STATUS_NEW = u'new'
903 STATUS_NEW = u'new'
905 STATUS_OPEN = u'open'
904 STATUS_OPEN = u'open'
906 STATUS_CLOSED = u'closed'
905 STATUS_CLOSED = u'closed'
907
906
908 pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True)
907 pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True)
909 title = Column('title', Unicode(256), nullable=True)
908 title = Column('title', Unicode(256), nullable=True)
910 description = Column('description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), nullable=True)
909 description = Column('description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), nullable=True)
911 status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW)
910 status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW)
912 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
911 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
913 updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
912 updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
914 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
913 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
915 _revisions = Column('revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql'))
914 _revisions = Column('revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql'))
916 org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
915 org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
917 org_ref = Column('org_ref', Unicode(256), nullable=False)
916 org_ref = Column('org_ref', Unicode(256), nullable=False)
918 other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
917 other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
919 other_ref = Column('other_ref', Unicode(256), nullable=False)
918 other_ref = Column('other_ref', Unicode(256), nullable=False)
920
919
921 author = relationship('User', lazy='joined')
920 author = relationship('User', lazy='joined')
922 reviewers = relationship('PullRequestReviewers',
921 reviewers = relationship('PullRequestReviewers',
923 cascade="all, delete, delete-orphan")
922 cascade="all, delete, delete-orphan")
924 org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id')
923 org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id')
925 other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id')
924 other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id')
926 statuses = relationship('ChangesetStatus')
925 statuses = relationship('ChangesetStatus')
927 comments = relationship('ChangesetComment',
926 comments = relationship('ChangesetComment',
928 cascade="all, delete, delete-orphan")
927 cascade="all, delete, delete-orphan")
929
928
930
929
931 class PullRequestReviewers(Base, BaseModel):
930 class PullRequestReviewers(Base, BaseModel):
932 __tablename__ = 'pull_request_reviewers'
931 __tablename__ = 'pull_request_reviewers'
933 __table_args__ = (
932 __table_args__ = (
934 {'extend_existing': True, 'mysql_engine': 'InnoDB',
933 {'extend_existing': True, 'mysql_engine': 'InnoDB',
935 'mysql_charset': 'utf8'},
934 'mysql_charset': 'utf8'},
936 )
935 )
937
936
938 def __init__(self, user=None, pull_request=None):
937 def __init__(self, user=None, pull_request=None):
939 self.user = user
938 self.user = user
940 self.pull_request = pull_request
939 self.pull_request = pull_request
941
940
942 pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True)
941 pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True)
943 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False)
942 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False)
944 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True)
943 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True)
945
944
946 user = relationship('User')
945 user = relationship('User')
947 pull_request = relationship('PullRequest')
946 pull_request = relationship('PullRequest')
948
947
949
948
950 class Notification(Base, BaseModel):
949 class Notification(Base, BaseModel):
951 __tablename__ = 'notifications'
950 __tablename__ = 'notifications'
952 __table_args__ = (
951 __table_args__ = (
953 Index('notification_type_idx', 'type'),
952 Index('notification_type_idx', 'type'),
954 {'extend_existing': True, 'mysql_engine': 'InnoDB',
953 {'extend_existing': True, 'mysql_engine': 'InnoDB',
955 'mysql_charset': 'utf8'},
954 'mysql_charset': 'utf8'},
956 )
955 )
957
956
958 TYPE_CHANGESET_COMMENT = u'cs_comment'
957 TYPE_CHANGESET_COMMENT = u'cs_comment'
959 TYPE_MESSAGE = u'message'
958 TYPE_MESSAGE = u'message'
960 TYPE_MENTION = u'mention'
959 TYPE_MENTION = u'mention'
961 TYPE_REGISTRATION = u'registration'
960 TYPE_REGISTRATION = u'registration'
962 TYPE_PULL_REQUEST = u'pull_request'
961 TYPE_PULL_REQUEST = u'pull_request'
963 TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment'
962 TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment'
964
963
965 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
964 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
966 subject = Column('subject', Unicode(512), nullable=True)
965 subject = Column('subject', Unicode(512), nullable=True)
967 body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True)
966 body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True)
968 created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
967 created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
969 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
968 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
970 type_ = Column('type', Unicode(256))
969 type_ = Column('type', Unicode(256))
971
970
972 created_by_user = relationship('User')
971 created_by_user = relationship('User')
973 notifications_to_users = relationship('UserNotification', lazy='joined',
972 notifications_to_users = relationship('UserNotification', lazy='joined',
974 cascade="all, delete, delete-orphan")
973 cascade="all, delete, delete-orphan")
975
974
976
975
977 class UserNotification(Base, BaseModel):
976 class UserNotification(Base, BaseModel):
978 __tablename__ = 'user_to_notification'
977 __tablename__ = 'user_to_notification'
979 __table_args__ = (
978 __table_args__ = (
980 UniqueConstraint('user_id', 'notification_id'),
979 UniqueConstraint('user_id', 'notification_id'),
981 {'extend_existing': True, 'mysql_engine': 'InnoDB',
980 {'extend_existing': True, 'mysql_engine': 'InnoDB',
982 'mysql_charset': 'utf8'}
981 'mysql_charset': 'utf8'}
983 )
982 )
984 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
983 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
985 notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
984 notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
986 read = Column('read', Boolean, default=False)
985 read = Column('read', Boolean, default=False)
987 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
986 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
988
987
989 user = relationship('User', lazy="joined")
988 user = relationship('User', lazy="joined")
990 notification = relationship('Notification', lazy="joined",
989 notification = relationship('Notification', lazy="joined",
991 order_by=lambda: Notification.created_on.desc(),)
990 order_by=lambda: Notification.created_on.desc(),)
992
991
993
992
994 class DbMigrateVersion(Base, BaseModel):
993 class DbMigrateVersion(Base, BaseModel):
995 __tablename__ = 'db_migrate_version'
994 __tablename__ = 'db_migrate_version'
996 __table_args__ = (
995 __table_args__ = (
997 {'extend_existing': True, 'mysql_engine': 'InnoDB',
996 {'extend_existing': True, 'mysql_engine': 'InnoDB',
998 'mysql_charset': 'utf8'},
997 'mysql_charset': 'utf8'},
999 )
998 )
1000 repository_id = Column('repository_id', String(250), primary_key=True)
999 repository_id = Column('repository_id', String(250), primary_key=True)
1001 repository_path = Column('repository_path', Text)
1000 repository_path = Column('repository_path', Text)
1002 version = Column('version', Integer)
1001 version = Column('version', Integer)
@@ -1,1085 +1,1084 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2019 RhodeCode GmbH
3 # Copyright (C) 2010-2019 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import os
21 import os
22 import time
22 import time
23 import logging
23 import logging
24 import datetime
24 import datetime
25 import traceback
25 import traceback
26 import hashlib
26 import hashlib
27 import collections
27 import collections
28
28
29 from sqlalchemy import *
29 from sqlalchemy import *
30 from sqlalchemy.ext.hybrid import hybrid_property
30 from sqlalchemy.ext.hybrid import hybrid_property
31 from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
31 from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
32 from sqlalchemy.exc import DatabaseError
32 from sqlalchemy.exc import DatabaseError
33 from beaker.cache import cache_region, region_invalidate
33 from beaker.cache import cache_region, region_invalidate
34 from webob.exc import HTTPNotFound
34 from webob.exc import HTTPNotFound
35
35
36 from rhodecode.translation import _
36 from rhodecode.translation import _
37
37
38 from rhodecode.lib.vcs import get_backend
38 from rhodecode.lib.vcs import get_backend
39 from rhodecode.lib.vcs.utils.helpers import get_scm
39 from rhodecode.lib.vcs.utils.helpers import get_scm
40 from rhodecode.lib.vcs.exceptions import VCSError
40 from rhodecode.lib.vcs.exceptions import VCSError
41 from zope.cachedescriptors.property import Lazy as LazyProperty
41 from zope.cachedescriptors.property import Lazy as LazyProperty
42 from rhodecode.lib.vcs.backends.base import EmptyCommit
42 from rhodecode.lib.vcs.backends.base import EmptyCommit
43
43
44 from rhodecode.lib.utils2 import str2bool, safe_str, get_commit_safe, \
44 from rhodecode.lib.utils2 import str2bool, safe_str, get_commit_safe, \
45 safe_unicode, remove_suffix, remove_prefix, time_to_datetime
45 safe_unicode, remove_suffix, remove_prefix, time_to_datetime
46 from rhodecode.lib.ext_json import json
46 from rhodecode.lib.ext_json import json
47 from rhodecode.lib.caching_query import FromCache
47 from rhodecode.lib.caching_query import FromCache
48
48
49 from rhodecode.model.meta import Base, Session
49 from rhodecode.model.meta import Base, Session
50
50
51 URL_SEP = '/'
51 URL_SEP = '/'
52 log = logging.getLogger(__name__)
52 log = logging.getLogger(__name__)
53
53
54 #==============================================================================
54 #==============================================================================
55 # BASE CLASSES
55 # BASE CLASSES
56 #==============================================================================
56 #==============================================================================
57
57
58 _hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest()
58 _hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest()
59
59
60
60
61 class BaseModel(object):
61 class BaseModel(object):
62 """
62 """
63 Base Model for all classes
63 Base Model for all classes
64 """
64 """
65
65
66 @classmethod
66 @classmethod
67 def _get_keys(cls):
67 def _get_keys(cls):
68 """return column names for this model """
68 """return column names for this model """
69 return class_mapper(cls).c.keys()
69 return class_mapper(cls).c.keys()
70
70
71 def get_dict(self):
71 def get_dict(self):
72 """
72 """
73 return dict with keys and values corresponding
73 return dict with keys and values corresponding
74 to this model data """
74 to this model data """
75
75
76 d = {}
76 d = {}
77 for k in self._get_keys():
77 for k in self._get_keys():
78 d[k] = getattr(self, k)
78 d[k] = getattr(self, k)
79
79
80 # also use __json__() if present to get additional fields
80 # also use __json__() if present to get additional fields
81 _json_attr = getattr(self, '__json__', None)
81 _json_attr = getattr(self, '__json__', None)
82 if _json_attr:
82 if _json_attr:
83 # update with attributes from __json__
83 # update with attributes from __json__
84 if callable(_json_attr):
84 if callable(_json_attr):
85 _json_attr = _json_attr()
85 _json_attr = _json_attr()
86 for k, val in _json_attr.iteritems():
86 for k, val in _json_attr.iteritems():
87 d[k] = val
87 d[k] = val
88 return d
88 return d
89
89
90 def get_appstruct(self):
90 def get_appstruct(self):
91 """return list with keys and values tupples corresponding
91 """return list with keys and values tupples corresponding
92 to this model data """
92 to this model data """
93
93
94 l = []
94 l = []
95 for k in self._get_keys():
95 for k in self._get_keys():
96 l.append((k, getattr(self, k),))
96 l.append((k, getattr(self, k),))
97 return l
97 return l
98
98
99 def populate_obj(self, populate_dict):
99 def populate_obj(self, populate_dict):
100 """populate model with data from given populate_dict"""
100 """populate model with data from given populate_dict"""
101
101
102 for k in self._get_keys():
102 for k in self._get_keys():
103 if k in populate_dict:
103 if k in populate_dict:
104 setattr(self, k, populate_dict[k])
104 setattr(self, k, populate_dict[k])
105
105
106 @classmethod
106 @classmethod
107 def query(cls):
107 def query(cls):
108 return Session().query(cls)
108 return Session().query(cls)
109
109
110 @classmethod
110 @classmethod
111 def get(cls, id_):
111 def get(cls, id_):
112 if id_:
112 if id_:
113 return cls.query().get(id_)
113 return cls.query().get(id_)
114
114
115 @classmethod
115 @classmethod
116 def get_or_404(cls, id_):
116 def get_or_404(cls, id_):
117 try:
117 try:
118 id_ = int(id_)
118 id_ = int(id_)
119 except (TypeError, ValueError):
119 except (TypeError, ValueError):
120 raise HTTPNotFound
120 raise HTTPNotFound
121
121
122 res = cls.query().get(id_)
122 res = cls.query().get(id_)
123 if not res:
123 if not res:
124 raise HTTPNotFound
124 raise HTTPNotFound
125 return res
125 return res
126
126
127 @classmethod
127 @classmethod
128 def getAll(cls):
128 def getAll(cls):
129 # deprecated and left for backward compatibility
129 # deprecated and left for backward compatibility
130 return cls.get_all()
130 return cls.get_all()
131
131
132 @classmethod
132 @classmethod
133 def get_all(cls):
133 def get_all(cls):
134 return cls.query().all()
134 return cls.query().all()
135
135
136 @classmethod
136 @classmethod
137 def delete(cls, id_):
137 def delete(cls, id_):
138 obj = cls.query().get(id_)
138 obj = cls.query().get(id_)
139 Session().delete(obj)
139 Session().delete(obj)
140
140
141 def __repr__(self):
141 def __repr__(self):
142 if hasattr(self, '__unicode__'):
142 if hasattr(self, '__unicode__'):
143 # python repr needs to return str
143 # python repr needs to return str
144 return safe_str(self.__unicode__())
144 return safe_str(self.__unicode__())
145 return '<DB:%s>' % (self.__class__.__name__)
145 return '<DB:%s>' % (self.__class__.__name__)
146
146
147
147
148 class RhodeCodeSetting(Base, BaseModel):
148 class RhodeCodeSetting(Base, BaseModel):
149 __tablename__ = 'rhodecode_settings'
149 __tablename__ = 'rhodecode_settings'
150 __table_args__ = (
150 __table_args__ = (
151 UniqueConstraint('app_settings_name'),
151 UniqueConstraint('app_settings_name'),
152 {'extend_existing': True, 'mysql_engine': 'InnoDB',
152 {'extend_existing': True, 'mysql_engine': 'InnoDB',
153 'mysql_charset': 'utf8'}
153 'mysql_charset': 'utf8'}
154 )
154 )
155 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
155 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
156 app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None)
156 app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None)
157 _app_settings_value = Column("app_settings_value", String(255), nullable=True, unique=None, default=None)
157 _app_settings_value = Column("app_settings_value", String(255), nullable=True, unique=None, default=None)
158
158
159 def __init__(self, k='', v=''):
159 def __init__(self, k='', v=''):
160 self.app_settings_name = k
160 self.app_settings_name = k
161 self.app_settings_value = v
161 self.app_settings_value = v
162
162
163 @validates('_app_settings_value')
163 @validates('_app_settings_value')
164 def validate_settings_value(self, key, val):
164 def validate_settings_value(self, key, val):
165 assert type(val) == unicode
165 assert type(val) == unicode
166 return val
166 return val
167
167
168 @hybrid_property
168 @hybrid_property
169 def app_settings_value(self):
169 def app_settings_value(self):
170 v = self._app_settings_value
170 v = self._app_settings_value
171 if self.app_settings_name in ["ldap_active",
171 if self.app_settings_name in ["ldap_active",
172 "default_repo_enable_statistics",
172 "default_repo_enable_statistics",
173 "default_repo_enable_locking",
173 "default_repo_enable_locking",
174 "default_repo_private",
174 "default_repo_private",
175 "default_repo_enable_downloads"]:
175 "default_repo_enable_downloads"]:
176 v = str2bool(v)
176 v = str2bool(v)
177 return v
177 return v
178
178
179 @app_settings_value.setter
179 @app_settings_value.setter
180 def app_settings_value(self, val):
180 def app_settings_value(self, val):
181 """
181 """
182 Setter that will always make sure we use unicode in app_settings_value
182 Setter that will always make sure we use unicode in app_settings_value
183
183
184 :param val:
184 :param val:
185 """
185 """
186 self._app_settings_value = safe_unicode(val)
186 self._app_settings_value = safe_unicode(val)
187
187
188 def __unicode__(self):
188 def __unicode__(self):
189 return u"<%s('%s:%s')>" % (
189 return u"<%s('%s:%s')>" % (
190 self.__class__.__name__,
190 self.__class__.__name__,
191 self.app_settings_name, self.app_settings_value
191 self.app_settings_name, self.app_settings_value
192 )
192 )
193
193
194
194
195 class RhodeCodeUi(Base, BaseModel):
195 class RhodeCodeUi(Base, BaseModel):
196 __tablename__ = 'rhodecode_ui'
196 __tablename__ = 'rhodecode_ui'
197 __table_args__ = (
197 __table_args__ = (
198 UniqueConstraint('ui_key'),
198 UniqueConstraint('ui_key'),
199 {'extend_existing': True, 'mysql_engine': 'InnoDB',
199 {'extend_existing': True, 'mysql_engine': 'InnoDB',
200 'mysql_charset': 'utf8'}
200 'mysql_charset': 'utf8'}
201 )
201 )
202
202
203 HOOK_REPO_SIZE = 'changegroup.repo_size'
203 HOOK_REPO_SIZE = 'changegroup.repo_size'
204 HOOK_PUSH = 'changegroup.push_logger'
204 HOOK_PUSH = 'changegroup.push_logger'
205 HOOK_PRE_PUSH = 'prechangegroup.pre_push'
205 HOOK_PRE_PUSH = 'prechangegroup.pre_push'
206 HOOK_PULL = 'outgoing.pull_logger'
206 HOOK_PULL = 'outgoing.pull_logger'
207 HOOK_PRE_PULL = 'preoutgoing.pre_pull'
207 HOOK_PRE_PULL = 'preoutgoing.pre_pull'
208
208
209 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
209 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
210 ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None)
210 ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None)
211 ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None)
211 ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None)
212 ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None)
212 ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None)
213 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
213 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
214
214
215
215
216
216
217 class User(Base, BaseModel):
217 class User(Base, BaseModel):
218 __tablename__ = 'users'
218 __tablename__ = 'users'
219 __table_args__ = (
219 __table_args__ = (
220 UniqueConstraint('username'), UniqueConstraint('email'),
220 UniqueConstraint('username'), UniqueConstraint('email'),
221 Index('u_username_idx', 'username'),
221 Index('u_username_idx', 'username'),
222 Index('u_email_idx', 'email'),
222 Index('u_email_idx', 'email'),
223 {'extend_existing': True, 'mysql_engine': 'InnoDB',
223 {'extend_existing': True, 'mysql_engine': 'InnoDB',
224 'mysql_charset': 'utf8'}
224 'mysql_charset': 'utf8'}
225 )
225 )
226 DEFAULT_USER = 'default'
226 DEFAULT_USER = 'default'
227 DEFAULT_PERMISSIONS = [
227 DEFAULT_PERMISSIONS = [
228 'hg.register.manual_activate', 'hg.create.repository',
228 'hg.register.manual_activate', 'hg.create.repository',
229 'hg.fork.repository', 'repository.read', 'group.read'
229 'hg.fork.repository', 'repository.read', 'group.read'
230 ]
230 ]
231 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
231 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
232 username = Column("username", String(255), nullable=True, unique=None, default=None)
232 username = Column("username", String(255), nullable=True, unique=None, default=None)
233 password = Column("password", String(255), nullable=True, unique=None, default=None)
233 password = Column("password", String(255), nullable=True, unique=None, default=None)
234 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
234 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
235 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
235 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
236 name = Column("firstname", String(255), nullable=True, unique=None, default=None)
236 name = Column("firstname", String(255), nullable=True, unique=None, default=None)
237 lastname = Column("lastname", String(255), nullable=True, unique=None, default=None)
237 lastname = Column("lastname", String(255), nullable=True, unique=None, default=None)
238 _email = Column("email", String(255), nullable=True, unique=None, default=None)
238 _email = Column("email", String(255), nullable=True, unique=None, default=None)
239 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
239 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
240 ldap_dn = Column("ldap_dn", String(255), nullable=True, unique=None, default=None)
240 ldap_dn = Column("ldap_dn", String(255), nullable=True, unique=None, default=None)
241 api_key = Column("api_key", String(255), nullable=True, unique=None, default=None)
241 api_key = Column("api_key", String(255), nullable=True, unique=None, default=None)
242 inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
242 inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
243
243
244 user_log = relationship('UserLog')
244 user_log = relationship('UserLog')
245 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
245 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
246
246
247 repositories = relationship('Repository')
247 repositories = relationship('Repository')
248 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
248 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
249 followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all')
249 followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all')
250
250
251 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
251 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
252 repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all')
252 repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all')
253
253
254 group_member = relationship('UserGroupMember', cascade='all')
254 group_member = relationship('UserGroupMember', cascade='all')
255
255
256 notifications = relationship('UserNotification', cascade='all')
256 notifications = relationship('UserNotification', cascade='all')
257 # notifications assigned to this user
257 # notifications assigned to this user
258 user_created_notifications = relationship('Notification', cascade='all')
258 user_created_notifications = relationship('Notification', cascade='all')
259 # comments created by this user
259 # comments created by this user
260 user_comments = relationship('ChangesetComment', cascade='all')
260 user_comments = relationship('ChangesetComment', cascade='all')
261 user_emails = relationship('UserEmailMap', cascade='all')
261 user_emails = relationship('UserEmailMap', cascade='all')
262
262
263 @hybrid_property
263 @hybrid_property
264 def email(self):
264 def email(self):
265 return self._email
265 return self._email
266
266
267 @email.setter
267 @email.setter
268 def email(self, val):
268 def email(self, val):
269 self._email = val.lower() if val else None
269 self._email = val.lower() if val else None
270
270
271 @property
271 @property
272 def firstname(self):
272 def firstname(self):
273 # alias for future
273 # alias for future
274 return self.name
274 return self.name
275
275
276 @property
276 @property
277 def username_and_name(self):
277 def username_and_name(self):
278 return '%s (%s %s)' % (self.username, self.firstname, self.lastname)
278 return '%s (%s %s)' % (self.username, self.firstname, self.lastname)
279
279
280 @property
280 @property
281 def full_name(self):
281 def full_name(self):
282 return '%s %s' % (self.firstname, self.lastname)
282 return '%s %s' % (self.firstname, self.lastname)
283
283
284 @property
284 @property
285 def full_contact(self):
285 def full_contact(self):
286 return '%s %s <%s>' % (self.firstname, self.lastname, self.email)
286 return '%s %s <%s>' % (self.firstname, self.lastname, self.email)
287
287
288 @property
288 @property
289 def short_contact(self):
289 def short_contact(self):
290 return '%s %s' % (self.firstname, self.lastname)
290 return '%s %s' % (self.firstname, self.lastname)
291
291
292 @property
292 @property
293 def is_admin(self):
293 def is_admin(self):
294 return self.admin
294 return self.admin
295
295
296 @classmethod
296 @classmethod
297 def get_by_username(cls, username, case_insensitive=False, cache=False):
297 def get_by_username(cls, username, case_insensitive=False, cache=False):
298 if case_insensitive:
298 if case_insensitive:
299 q = cls.query().filter(cls.username.ilike(username))
299 q = cls.query().filter(cls.username.ilike(username))
300 else:
300 else:
301 q = cls.query().filter(cls.username == username)
301 q = cls.query().filter(cls.username == username)
302
302
303 if cache:
303 if cache:
304 q = q.options(FromCache(
304 q = q.options(FromCache(
305 "sql_cache_short",
305 "sql_cache_short",
306 "get_user_%s" % _hash_key(username)
306 "get_user_%s" % _hash_key(username)
307 )
307 )
308 )
308 )
309 return q.scalar()
309 return q.scalar()
310
310
311 @classmethod
311 @classmethod
312 def get_by_auth_token(cls, auth_token, cache=False):
312 def get_by_auth_token(cls, auth_token, cache=False):
313 q = cls.query().filter(cls.api_key == auth_token)
313 q = cls.query().filter(cls.api_key == auth_token)
314
314
315 if cache:
315 if cache:
316 q = q.options(FromCache("sql_cache_short",
316 q = q.options(FromCache("sql_cache_short",
317 "get_auth_token_%s" % auth_token))
317 "get_auth_token_%s" % auth_token))
318 return q.scalar()
318 return q.scalar()
319
319
320 @classmethod
320 @classmethod
321 def get_by_email(cls, email, case_insensitive=False, cache=False):
321 def get_by_email(cls, email, case_insensitive=False, cache=False):
322 if case_insensitive:
322 if case_insensitive:
323 q = cls.query().filter(cls.email.ilike(email))
323 q = cls.query().filter(cls.email.ilike(email))
324 else:
324 else:
325 q = cls.query().filter(cls.email == email)
325 q = cls.query().filter(cls.email == email)
326
326
327 if cache:
327 if cache:
328 q = q.options(FromCache("sql_cache_short",
328 q = q.options(FromCache("sql_cache_short",
329 "get_email_key_%s" % email))
329 "get_email_key_%s" % email))
330
330
331 ret = q.scalar()
331 ret = q.scalar()
332 if ret is None:
332 if ret is None:
333 q = UserEmailMap.query()
333 q = UserEmailMap.query()
334 # try fetching in alternate email map
334 # try fetching in alternate email map
335 if case_insensitive:
335 if case_insensitive:
336 q = q.filter(UserEmailMap.email.ilike(email))
336 q = q.filter(UserEmailMap.email.ilike(email))
337 else:
337 else:
338 q = q.filter(UserEmailMap.email == email)
338 q = q.filter(UserEmailMap.email == email)
339 q = q.options(joinedload(UserEmailMap.user))
339 q = q.options(joinedload(UserEmailMap.user))
340 if cache:
340 if cache:
341 q = q.options(FromCache("sql_cache_short",
341 q = q.options(FromCache("sql_cache_short",
342 "get_email_map_key_%s" % email))
342 "get_email_map_key_%s" % email))
343 ret = getattr(q.scalar(), 'user', None)
343 ret = getattr(q.scalar(), 'user', None)
344
344
345 return ret
345 return ret
346
346
347
347
348 class UserEmailMap(Base, BaseModel):
348 class UserEmailMap(Base, BaseModel):
349 __tablename__ = 'user_email_map'
349 __tablename__ = 'user_email_map'
350 __table_args__ = (
350 __table_args__ = (
351 Index('uem_email_idx', 'email'),
351 Index('uem_email_idx', 'email'),
352 UniqueConstraint('email'),
352 UniqueConstraint('email'),
353 {'extend_existing': True, 'mysql_engine': 'InnoDB',
353 {'extend_existing': True, 'mysql_engine': 'InnoDB',
354 'mysql_charset': 'utf8'}
354 'mysql_charset': 'utf8'}
355 )
355 )
356 __mapper_args__ = {}
356 __mapper_args__ = {}
357
357
358 email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
358 email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
359 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
359 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
360 _email = Column("email", String(255), nullable=True, unique=False, default=None)
360 _email = Column("email", String(255), nullable=True, unique=False, default=None)
361 user = relationship('User', lazy='joined')
361 user = relationship('User', lazy='joined')
362
362
363 @validates('_email')
363 @validates('_email')
364 def validate_email(self, key, email):
364 def validate_email(self, key, email):
365 # check if this email is not main one
365 # check if this email is not main one
366 main_email = Session().query(User).filter(User.email == email).scalar()
366 main_email = Session().query(User).filter(User.email == email).scalar()
367 if main_email is not None:
367 if main_email is not None:
368 raise AttributeError('email %s is present is user table' % email)
368 raise AttributeError('email %s is present is user table' % email)
369 return email
369 return email
370
370
371 @hybrid_property
371 @hybrid_property
372 def email(self):
372 def email(self):
373 return self._email
373 return self._email
374
374
375 @email.setter
375 @email.setter
376 def email(self, val):
376 def email(self, val):
377 self._email = val.lower() if val else None
377 self._email = val.lower() if val else None
378
378
379
379
380 class UserIpMap(Base, BaseModel):
380 class UserIpMap(Base, BaseModel):
381 __tablename__ = 'user_ip_map'
381 __tablename__ = 'user_ip_map'
382 __table_args__ = (
382 __table_args__ = (
383 UniqueConstraint('user_id', 'ip_addr'),
383 UniqueConstraint('user_id', 'ip_addr'),
384 {'extend_existing': True, 'mysql_engine': 'InnoDB',
384 {'extend_existing': True, 'mysql_engine': 'InnoDB',
385 'mysql_charset': 'utf8'}
385 'mysql_charset': 'utf8'}
386 )
386 )
387 __mapper_args__ = {}
387 __mapper_args__ = {}
388
388
389 ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
389 ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
390 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
390 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
391 ip_addr = Column("ip_addr", String(255), nullable=True, unique=False, default=None)
391 ip_addr = Column("ip_addr", String(255), nullable=True, unique=False, default=None)
392 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
392 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
393 user = relationship('User', lazy='joined')
393 user = relationship('User', lazy='joined')
394
394
395
395
396 class UserLog(Base, BaseModel):
396 class UserLog(Base, BaseModel):
397 __tablename__ = 'user_logs'
397 __tablename__ = 'user_logs'
398 __table_args__ = (
398 __table_args__ = (
399 {'extend_existing': True, 'mysql_engine': 'InnoDB',
399 {'extend_existing': True, 'mysql_engine': 'InnoDB',
400 'mysql_charset': 'utf8'},
400 'mysql_charset': 'utf8'},
401 )
401 )
402 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
402 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
403 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
403 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
404 username = Column("username", String(255), nullable=True, unique=None, default=None)
404 username = Column("username", String(255), nullable=True, unique=None, default=None)
405 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
405 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
406 repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None)
406 repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None)
407 user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None)
407 user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None)
408 action = Column("action", String(1200000), nullable=True, unique=None, default=None)
408 action = Column("action", String(1200000), nullable=True, unique=None, default=None)
409 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
409 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
410
410
411
411
412 user = relationship('User')
412 user = relationship('User')
413 repository = relationship('Repository', cascade='')
413 repository = relationship('Repository', cascade='')
414
414
415
415
416 class UserGroup(Base, BaseModel):
416 class UserGroup(Base, BaseModel):
417 __tablename__ = 'users_groups'
417 __tablename__ = 'users_groups'
418 __table_args__ = (
418 __table_args__ = (
419 {'extend_existing': True, 'mysql_engine': 'InnoDB',
419 {'extend_existing': True, 'mysql_engine': 'InnoDB',
420 'mysql_charset': 'utf8'},
420 'mysql_charset': 'utf8'},
421 )
421 )
422
422
423 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
423 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
424 users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None)
424 users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None)
425 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
425 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
426 inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
426 inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
427
427
428 members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
428 members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
429 users_group_to_perm = relationship('UserGroupToPerm', cascade='all')
429 users_group_to_perm = relationship('UserGroupToPerm', cascade='all')
430 users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
430 users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
431
431
432 def __unicode__(self):
432 def __unicode__(self):
433 return u'<userGroup(%s)>' % (self.users_group_name)
433 return u'<userGroup(%s)>' % (self.users_group_name)
434
434
435 @classmethod
435 @classmethod
436 def get_by_group_name(cls, group_name, cache=False,
436 def get_by_group_name(cls, group_name, cache=False,
437 case_insensitive=False):
437 case_insensitive=False):
438 if case_insensitive:
438 if case_insensitive:
439 q = cls.query().filter(cls.users_group_name.ilike(group_name))
439 q = cls.query().filter(cls.users_group_name.ilike(group_name))
440 else:
440 else:
441 q = cls.query().filter(cls.users_group_name == group_name)
441 q = cls.query().filter(cls.users_group_name == group_name)
442 if cache:
442 if cache:
443 q = q.options(FromCache(
443 q = q.options(FromCache(
444 "sql_cache_short",
444 "sql_cache_short",
445 "get_user_%s" % _hash_key(group_name)
445 "get_user_%s" % _hash_key(group_name)
446 )
446 )
447 )
447 )
448 return q.scalar()
448 return q.scalar()
449
449
450 @classmethod
450 @classmethod
451 def get(cls, users_group_id, cache=False):
451 def get(cls, users_group_id, cache=False):
452 user_group = cls.query()
452 user_group = cls.query()
453 if cache:
453 if cache:
454 user_group = user_group.options(FromCache("sql_cache_short",
454 user_group = user_group.options(FromCache("sql_cache_short",
455 "get_users_group_%s" % users_group_id))
455 "get_users_group_%s" % users_group_id))
456 return user_group.get(users_group_id)
456 return user_group.get(users_group_id)
457
457
458
458
459 class UserGroupMember(Base, BaseModel):
459 class UserGroupMember(Base, BaseModel):
460 __tablename__ = 'users_groups_members'
460 __tablename__ = 'users_groups_members'
461 __table_args__ = (
461 __table_args__ = (
462 {'extend_existing': True, 'mysql_engine': 'InnoDB',
462 {'extend_existing': True, 'mysql_engine': 'InnoDB',
463 'mysql_charset': 'utf8'},
463 'mysql_charset': 'utf8'},
464 )
464 )
465
465
466 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
466 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
467 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
467 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
468 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
468 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
469
469
470 user = relationship('User', lazy='joined')
470 user = relationship('User', lazy='joined')
471 users_group = relationship('UserGroup')
471 users_group = relationship('UserGroup')
472
472
473 def __init__(self, gr_id='', u_id=''):
473 def __init__(self, gr_id='', u_id=''):
474 self.users_group_id = gr_id
474 self.users_group_id = gr_id
475 self.user_id = u_id
475 self.user_id = u_id
476
476
477
477
478 class RepositoryField(Base, BaseModel):
478 class RepositoryField(Base, BaseModel):
479 __tablename__ = 'repositories_fields'
479 __tablename__ = 'repositories_fields'
480 __table_args__ = (
480 __table_args__ = (
481 UniqueConstraint('repository_id', 'field_key'), # no-multi field
481 UniqueConstraint('repository_id', 'field_key'), # no-multi field
482 {'extend_existing': True, 'mysql_engine': 'InnoDB',
482 {'extend_existing': True, 'mysql_engine': 'InnoDB',
483 'mysql_charset': 'utf8'},
483 'mysql_charset': 'utf8'},
484 )
484 )
485 PREFIX = 'ex_' # prefix used in form to not conflict with already existing fields
485 PREFIX = 'ex_' # prefix used in form to not conflict with already existing fields
486
486
487 repo_field_id = Column("repo_field_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
487 repo_field_id = Column("repo_field_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
488 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
488 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
489 field_key = Column("field_key", String(250))
489 field_key = Column("field_key", String(250))
490 field_label = Column("field_label", String(1024), nullable=False)
490 field_label = Column("field_label", String(1024), nullable=False)
491 field_value = Column("field_value", String(10000), nullable=False)
491 field_value = Column("field_value", String(10000), nullable=False)
492 field_desc = Column("field_desc", String(1024), nullable=False)
492 field_desc = Column("field_desc", String(1024), nullable=False)
493 field_type = Column("field_type", String(256), nullable=False, unique=None)
493 field_type = Column("field_type", String(256), nullable=False, unique=None)
494 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
494 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
495
495
496 repository = relationship('Repository')
496 repository = relationship('Repository')
497
497
498 @classmethod
498 @classmethod
499 def get_by_key_name(cls, key, repo):
499 def get_by_key_name(cls, key, repo):
500 row = cls.query()\
500 row = cls.query()\
501 .filter(cls.repository == repo)\
501 .filter(cls.repository == repo)\
502 .filter(cls.field_key == key).scalar()
502 .filter(cls.field_key == key).scalar()
503 return row
503 return row
504
504
505
505
506 class Repository(Base, BaseModel):
506 class Repository(Base, BaseModel):
507 __tablename__ = 'repositories'
507 __tablename__ = 'repositories'
508 __table_args__ = (
508 __table_args__ = (
509 UniqueConstraint('repo_name'),
509 UniqueConstraint('repo_name'),
510 Index('r_repo_name_idx', 'repo_name'),
510 Index('r_repo_name_idx', 'repo_name'),
511 {'extend_existing': True, 'mysql_engine': 'InnoDB',
511 {'extend_existing': True, 'mysql_engine': 'InnoDB',
512 'mysql_charset': 'utf8'},
512 'mysql_charset': 'utf8'},
513 )
513 )
514
514
515 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
515 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
516 repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None)
516 repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None)
517 clone_uri = Column("clone_uri", String(255), nullable=True, unique=False, default=None)
517 clone_uri = Column("clone_uri", String(255), nullable=True, unique=False, default=None)
518 repo_type = Column("repo_type", String(255), nullable=False, unique=False, default=None)
518 repo_type = Column("repo_type", String(255), nullable=False, unique=False, default=None)
519 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
519 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
520 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
520 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
521 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
521 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
522 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
522 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
523 description = Column("description", String(10000), nullable=True, unique=None, default=None)
523 description = Column("description", String(10000), nullable=True, unique=None, default=None)
524 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
524 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
525 updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
525 updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
526 landing_rev = Column("landing_revision", String(255), nullable=False, unique=False, default=None)
526 landing_rev = Column("landing_revision", String(255), nullable=False, unique=False, default=None)
527 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
527 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
528 _locked = Column("locked", String(255), nullable=True, unique=False, default=None)
528 _locked = Column("locked", String(255), nullable=True, unique=False, default=None)
529 _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) #JSON data
529 _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) #JSON data
530
530
531 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
531 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
532 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
532 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
533
533
534 user = relationship('User')
534 user = relationship('User')
535 fork = relationship('Repository', remote_side=repo_id)
535 fork = relationship('Repository', remote_side=repo_id)
536 group = relationship('RepoGroup')
536 group = relationship('RepoGroup')
537 repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
537 repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
538 users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
538 users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
539 stats = relationship('Statistics', cascade='all', uselist=False)
539 stats = relationship('Statistics', cascade='all', uselist=False)
540
540
541 followers = relationship('UserFollowing',
541 followers = relationship('UserFollowing',
542 primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id',
542 primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id',
543 cascade='all')
543 cascade='all')
544 extra_fields = relationship('RepositoryField',
544 extra_fields = relationship('RepositoryField',
545 cascade="all, delete, delete-orphan")
545 cascade="all, delete, delete-orphan")
546
546
547 logs = relationship('UserLog')
547 logs = relationship('UserLog')
548 comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan")
548 comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan")
549
549
550 pull_requests_org = relationship('PullRequest',
550 pull_requests_org = relationship('PullRequest',
551 primaryjoin='PullRequest.org_repo_id==Repository.repo_id',
551 primaryjoin='PullRequest.org_repo_id==Repository.repo_id',
552 cascade="all, delete, delete-orphan")
552 cascade="all, delete, delete-orphan")
553
553
554 pull_requests_other = relationship('PullRequest',
554 pull_requests_other = relationship('PullRequest',
555 primaryjoin='PullRequest.other_repo_id==Repository.repo_id',
555 primaryjoin='PullRequest.other_repo_id==Repository.repo_id',
556 cascade="all, delete, delete-orphan")
556 cascade="all, delete, delete-orphan")
557
557
558 def __unicode__(self):
558 def __unicode__(self):
559 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id,
559 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id,
560 safe_unicode(self.repo_name))
560 safe_unicode(self.repo_name))
561
561
562 #NOTE for this migration we are required tio have it
562 #NOTE for this migration we are required tio have it
563 @hybrid_property
563 @hybrid_property
564 def changeset_cache(self):
564 def changeset_cache(self):
565 from rhodecode.lib.vcs.backends.base import EmptyCommit
565 from rhodecode.lib.vcs.backends.base import EmptyCommit
566 dummy = EmptyCommit().__json__()
566 dummy = EmptyCommit().__json__()
567 if not self._changeset_cache:
567 if not self._changeset_cache:
568 return dummy
568 return dummy
569 try:
569 try:
570 return json.loads(self._changeset_cache)
570 return json.loads(self._changeset_cache)
571 except TypeError:
571 except TypeError:
572 return dummy
572 return dummy
573
573
574 @changeset_cache.setter
574 @changeset_cache.setter
575 def changeset_cache(self, val):
575 def changeset_cache(self, val):
576 try:
576 try:
577 self._changeset_cache = json.dumps(val)
577 self._changeset_cache = json.dumps(val)
578 except Exception:
578 except Exception:
579 log.error(traceback.format_exc())
579 log.error(traceback.format_exc())
580
580
581 @classmethod
581 @classmethod
582 def get_by_repo_name(cls, repo_name):
582 def get_by_repo_name(cls, repo_name):
583 q = Session().query(cls).filter(cls.repo_name == repo_name)
583 q = Session().query(cls).filter(cls.repo_name == repo_name)
584 q = q.options(joinedload(Repository.fork))\
584 q = q.options(joinedload(Repository.fork))\
585 .options(joinedload(Repository.user))\
585 .options(joinedload(Repository.user))\
586 .options(joinedload(Repository.group))
586 .options(joinedload(Repository.group))
587 return q.scalar()
587 return q.scalar()
588
588
589 #NOTE this is required for this migration to work
589 #NOTE this is required for this migration to work
590 def update_commit_cache(self, cs_cache=None):
590 def update_commit_cache(self, cs_cache=None):
591 """
591 """
592 Update cache of last changeset for repository, keys should be::
592 Update cache of last changeset for repository, keys should be::
593
593
594 short_id
594 short_id
595 raw_id
595 raw_id
596 revision
596 revision
597 message
597 message
598 date
598 date
599 author
599 author
600
600
601 :param cs_cache:
601 :param cs_cache:
602 """
602 """
603 from rhodecode.lib.vcs.backends.base import BaseChangeset
603 from rhodecode.lib.vcs.backends.base import BaseChangeset
604 if cs_cache is None:
604 if cs_cache is None:
605 cs_cache = EmptyCommit()
605 cs_cache = EmptyCommit()
606 # Note: Using always the empty commit here in case we are
606 # Note: Using always the empty commit here in case we are
607 # upgrading towards version 3.0 and above. Reason is that in this
607 # upgrading towards version 3.0 and above. Reason is that in this
608 # case the vcsclient connection is not available and things
608 # case the vcsclient connection is not available and things
609 # would explode here.
609 # would explode here.
610
610
611 if isinstance(cs_cache, BaseChangeset):
611 if isinstance(cs_cache, BaseChangeset):
612 cs_cache = cs_cache.__json__()
612 cs_cache = cs_cache.__json__()
613
613
614 if (cs_cache != self.changeset_cache or not self.changeset_cache):
614 if (cs_cache != self.changeset_cache or not self.changeset_cache):
615 _default = datetime.datetime.fromtimestamp(0)
615 _default = datetime.datetime.fromtimestamp(0)
616 last_change = cs_cache.get('date') or _default
616 last_change = cs_cache.get('date') or _default
617 log.debug('updated repo %s with new cs cache %s', self.repo_name, cs_cache)
617 log.debug('updated repo %s with new cs cache %s', self.repo_name, cs_cache)
618 self.updated_on = last_change
618 self.updated_on = last_change
619 self.changeset_cache = cs_cache
619 self.changeset_cache = cs_cache
620 Session().add(self)
620 Session().add(self)
621 Session().commit()
621 Session().commit()
622 else:
622 else:
623 log.debug('Skipping repo:%s already with latest changes', self.repo_name)
623 log.debug('Skipping repo:%s already with latest changes', self.repo_name)
624
624
625 class RepoGroup(Base, BaseModel):
625 class RepoGroup(Base, BaseModel):
626 __tablename__ = 'groups'
626 __tablename__ = 'groups'
627 __table_args__ = (
627 __table_args__ = (
628 UniqueConstraint('group_name', 'group_parent_id'),
628 UniqueConstraint('group_name', 'group_parent_id'),
629 CheckConstraint('group_id != group_parent_id'),
630 {'extend_existing': True, 'mysql_engine': 'InnoDB',
629 {'extend_existing': True, 'mysql_engine': 'InnoDB',
631 'mysql_charset': 'utf8'},
630 'mysql_charset': 'utf8'},
632 )
631 )
633 __mapper_args__ = {'order_by': 'group_name'}
632 __mapper_args__ = {'order_by': 'group_name'}
634
633
635 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
634 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
636 group_name = Column("group_name", String(255), nullable=False, unique=True, default=None)
635 group_name = Column("group_name", String(255), nullable=False, unique=True, default=None)
637 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
636 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
638 group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None)
637 group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None)
639 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
638 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
640
639
641 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
640 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
642 users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
641 users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
643 parent_group = relationship('RepoGroup', remote_side=group_id)
642 parent_group = relationship('RepoGroup', remote_side=group_id)
644
643
645 def __init__(self, group_name='', parent_group=None):
644 def __init__(self, group_name='', parent_group=None):
646 self.group_name = group_name
645 self.group_name = group_name
647 self.parent_group = parent_group
646 self.parent_group = parent_group
648
647
649 def __unicode__(self):
648 def __unicode__(self):
650 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
649 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
651 self.group_name)
650 self.group_name)
652
651
653 @classmethod
652 @classmethod
654 def url_sep(cls):
653 def url_sep(cls):
655 return URL_SEP
654 return URL_SEP
656
655
657 @classmethod
656 @classmethod
658 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
657 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
659 if case_insensitive:
658 if case_insensitive:
660 gr = cls.query()\
659 gr = cls.query()\
661 .filter(cls.group_name.ilike(group_name))
660 .filter(cls.group_name.ilike(group_name))
662 else:
661 else:
663 gr = cls.query()\
662 gr = cls.query()\
664 .filter(cls.group_name == group_name)
663 .filter(cls.group_name == group_name)
665 if cache:
664 if cache:
666 gr = gr.options(FromCache(
665 gr = gr.options(FromCache(
667 "sql_cache_short",
666 "sql_cache_short",
668 "get_group_%s" % _hash_key(group_name)
667 "get_group_%s" % _hash_key(group_name)
669 )
668 )
670 )
669 )
671 return gr.scalar()
670 return gr.scalar()
672
671
673
672
674 class Permission(Base, BaseModel):
673 class Permission(Base, BaseModel):
675 __tablename__ = 'permissions'
674 __tablename__ = 'permissions'
676 __table_args__ = (
675 __table_args__ = (
677 Index('p_perm_name_idx', 'permission_name'),
676 Index('p_perm_name_idx', 'permission_name'),
678 {'extend_existing': True, 'mysql_engine': 'InnoDB',
677 {'extend_existing': True, 'mysql_engine': 'InnoDB',
679 'mysql_charset': 'utf8'},
678 'mysql_charset': 'utf8'},
680 )
679 )
681 PERMS = [
680 PERMS = [
682 ('repository.none', _('Repository no access')),
681 ('repository.none', _('Repository no access')),
683 ('repository.read', _('Repository read access')),
682 ('repository.read', _('Repository read access')),
684 ('repository.write', _('Repository write access')),
683 ('repository.write', _('Repository write access')),
685 ('repository.admin', _('Repository admin access')),
684 ('repository.admin', _('Repository admin access')),
686
685
687 ('group.none', _('Repository group no access')),
686 ('group.none', _('Repository group no access')),
688 ('group.read', _('Repository group read access')),
687 ('group.read', _('Repository group read access')),
689 ('group.write', _('Repository group write access')),
688 ('group.write', _('Repository group write access')),
690 ('group.admin', _('Repository group admin access')),
689 ('group.admin', _('Repository group admin access')),
691
690
692 ('hg.admin', _('RhodeCode Administrator')),
691 ('hg.admin', _('RhodeCode Administrator')),
693 ('hg.create.none', _('Repository creation disabled')),
692 ('hg.create.none', _('Repository creation disabled')),
694 ('hg.create.repository', _('Repository creation enabled')),
693 ('hg.create.repository', _('Repository creation enabled')),
695 ('hg.fork.none', _('Repository forking disabled')),
694 ('hg.fork.none', _('Repository forking disabled')),
696 ('hg.fork.repository', _('Repository forking enabled')),
695 ('hg.fork.repository', _('Repository forking enabled')),
697 ('hg.register.none', _('Register disabled')),
696 ('hg.register.none', _('Register disabled')),
698 ('hg.register.manual_activate', _('Register new user with RhodeCode '
697 ('hg.register.manual_activate', _('Register new user with RhodeCode '
699 'with manual activation')),
698 'with manual activation')),
700
699
701 ('hg.register.auto_activate', _('Register new user with RhodeCode '
700 ('hg.register.auto_activate', _('Register new user with RhodeCode '
702 'with auto activation')),
701 'with auto activation')),
703 ]
702 ]
704
703
705 # defines which permissions are more important higher the more important
704 # defines which permissions are more important higher the more important
706 PERM_WEIGHTS = {
705 PERM_WEIGHTS = {
707 'repository.none': 0,
706 'repository.none': 0,
708 'repository.read': 1,
707 'repository.read': 1,
709 'repository.write': 3,
708 'repository.write': 3,
710 'repository.admin': 4,
709 'repository.admin': 4,
711
710
712 'group.none': 0,
711 'group.none': 0,
713 'group.read': 1,
712 'group.read': 1,
714 'group.write': 3,
713 'group.write': 3,
715 'group.admin': 4,
714 'group.admin': 4,
716
715
717 'hg.fork.none': 0,
716 'hg.fork.none': 0,
718 'hg.fork.repository': 1,
717 'hg.fork.repository': 1,
719 'hg.create.none': 0,
718 'hg.create.none': 0,
720 'hg.create.repository':1
719 'hg.create.repository':1
721 }
720 }
722
721
723 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
722 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
724 permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None)
723 permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None)
725 permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None)
724 permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None)
726
725
727 def __unicode__(self):
726 def __unicode__(self):
728 return u"<%s('%s:%s')>" % (
727 return u"<%s('%s:%s')>" % (
729 self.__class__.__name__, self.permission_id, self.permission_name
728 self.__class__.__name__, self.permission_id, self.permission_name
730 )
729 )
731
730
732 @classmethod
731 @classmethod
733 def get_by_key(cls, key):
732 def get_by_key(cls, key):
734 return cls.query().filter(cls.permission_name == key).scalar()
733 return cls.query().filter(cls.permission_name == key).scalar()
735
734
736
735
737 class UserRepoToPerm(Base, BaseModel):
736 class UserRepoToPerm(Base, BaseModel):
738 __tablename__ = 'repo_to_perm'
737 __tablename__ = 'repo_to_perm'
739 __table_args__ = (
738 __table_args__ = (
740 UniqueConstraint('user_id', 'repository_id', 'permission_id'),
739 UniqueConstraint('user_id', 'repository_id', 'permission_id'),
741 {'extend_existing': True, 'mysql_engine': 'InnoDB',
740 {'extend_existing': True, 'mysql_engine': 'InnoDB',
742 'mysql_charset': 'utf8'}
741 'mysql_charset': 'utf8'}
743 )
742 )
744 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
743 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
745 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
744 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
746 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
745 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
747 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
746 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
748
747
749 user = relationship('User')
748 user = relationship('User')
750 repository = relationship('Repository')
749 repository = relationship('Repository')
751 permission = relationship('Permission')
750 permission = relationship('Permission')
752
751
753 def __unicode__(self):
752 def __unicode__(self):
754 return u'<user:%s => %s >' % (self.user, self.repository)
753 return u'<user:%s => %s >' % (self.user, self.repository)
755
754
756
755
757 class UserToPerm(Base, BaseModel):
756 class UserToPerm(Base, BaseModel):
758 __tablename__ = 'user_to_perm'
757 __tablename__ = 'user_to_perm'
759 __table_args__ = (
758 __table_args__ = (
760 UniqueConstraint('user_id', 'permission_id'),
759 UniqueConstraint('user_id', 'permission_id'),
761 {'extend_existing': True, 'mysql_engine': 'InnoDB',
760 {'extend_existing': True, 'mysql_engine': 'InnoDB',
762 'mysql_charset': 'utf8'}
761 'mysql_charset': 'utf8'}
763 )
762 )
764 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
763 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
765 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
764 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
766 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
765 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
767
766
768 user = relationship('User')
767 user = relationship('User')
769 permission = relationship('Permission', lazy='joined')
768 permission = relationship('Permission', lazy='joined')
770
769
771
770
772 class UserGroupRepoToPerm(Base, BaseModel):
771 class UserGroupRepoToPerm(Base, BaseModel):
773 __tablename__ = 'users_group_repo_to_perm'
772 __tablename__ = 'users_group_repo_to_perm'
774 __table_args__ = (
773 __table_args__ = (
775 UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
774 UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
776 {'extend_existing': True, 'mysql_engine': 'InnoDB',
775 {'extend_existing': True, 'mysql_engine': 'InnoDB',
777 'mysql_charset': 'utf8'}
776 'mysql_charset': 'utf8'}
778 )
777 )
779 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
778 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
780 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
779 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
781 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
780 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
782 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
781 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
783
782
784 users_group = relationship('UserGroup')
783 users_group = relationship('UserGroup')
785 permission = relationship('Permission')
784 permission = relationship('Permission')
786 repository = relationship('Repository')
785 repository = relationship('Repository')
787
786
788 def __unicode__(self):
787 def __unicode__(self):
789 return u'<userGroup:%s => %s >' % (self.users_group, self.repository)
788 return u'<userGroup:%s => %s >' % (self.users_group, self.repository)
790
789
791
790
792 class UserGroupToPerm(Base, BaseModel):
791 class UserGroupToPerm(Base, BaseModel):
793 __tablename__ = 'users_group_to_perm'
792 __tablename__ = 'users_group_to_perm'
794 __table_args__ = (
793 __table_args__ = (
795 UniqueConstraint('users_group_id', 'permission_id',),
794 UniqueConstraint('users_group_id', 'permission_id',),
796 {'extend_existing': True, 'mysql_engine': 'InnoDB',
795 {'extend_existing': True, 'mysql_engine': 'InnoDB',
797 'mysql_charset': 'utf8'}
796 'mysql_charset': 'utf8'}
798 )
797 )
799 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
798 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
800 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
799 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
801 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
800 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
802
801
803 users_group = relationship('UserGroup')
802 users_group = relationship('UserGroup')
804 permission = relationship('Permission')
803 permission = relationship('Permission')
805
804
806
805
807 class UserRepoGroupToPerm(Base, BaseModel):
806 class UserRepoGroupToPerm(Base, BaseModel):
808 __tablename__ = 'user_repo_group_to_perm'
807 __tablename__ = 'user_repo_group_to_perm'
809 __table_args__ = (
808 __table_args__ = (
810 UniqueConstraint('user_id', 'group_id', 'permission_id'),
809 UniqueConstraint('user_id', 'group_id', 'permission_id'),
811 {'extend_existing': True, 'mysql_engine': 'InnoDB',
810 {'extend_existing': True, 'mysql_engine': 'InnoDB',
812 'mysql_charset': 'utf8'}
811 'mysql_charset': 'utf8'}
813 )
812 )
814
813
815 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
814 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
816 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
815 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
817 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
816 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
818 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
817 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
819
818
820 user = relationship('User')
819 user = relationship('User')
821 group = relationship('RepoGroup')
820 group = relationship('RepoGroup')
822 permission = relationship('Permission')
821 permission = relationship('Permission')
823
822
824
823
825 class UserGroupRepoGroupToPerm(Base, BaseModel):
824 class UserGroupRepoGroupToPerm(Base, BaseModel):
826 __tablename__ = 'users_group_repo_group_to_perm'
825 __tablename__ = 'users_group_repo_group_to_perm'
827 __table_args__ = (
826 __table_args__ = (
828 UniqueConstraint('users_group_id', 'group_id'),
827 UniqueConstraint('users_group_id', 'group_id'),
829 {'extend_existing': True, 'mysql_engine': 'InnoDB',
828 {'extend_existing': True, 'mysql_engine': 'InnoDB',
830 'mysql_charset': 'utf8'}
829 'mysql_charset': 'utf8'}
831 )
830 )
832
831
833 users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
832 users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
834 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
833 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
835 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
834 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
836 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
835 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
837
836
838 users_group = relationship('UserGroup')
837 users_group = relationship('UserGroup')
839 permission = relationship('Permission')
838 permission = relationship('Permission')
840 group = relationship('RepoGroup')
839 group = relationship('RepoGroup')
841
840
842
841
843 class Statistics(Base, BaseModel):
842 class Statistics(Base, BaseModel):
844 __tablename__ = 'statistics'
843 __tablename__ = 'statistics'
845 __table_args__ = (
844 __table_args__ = (
846 UniqueConstraint('repository_id'),
845 UniqueConstraint('repository_id'),
847 {'extend_existing': True, 'mysql_engine': 'InnoDB',
846 {'extend_existing': True, 'mysql_engine': 'InnoDB',
848 'mysql_charset': 'utf8'}
847 'mysql_charset': 'utf8'}
849 )
848 )
850 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
849 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
851 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
850 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
852 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
851 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
853 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
852 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
854 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
853 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
855 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
854 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
856
855
857 repository = relationship('Repository', single_parent=True)
856 repository = relationship('Repository', single_parent=True)
858
857
859
858
860 class UserFollowing(Base, BaseModel):
859 class UserFollowing(Base, BaseModel):
861 __tablename__ = 'user_followings'
860 __tablename__ = 'user_followings'
862 __table_args__ = (
861 __table_args__ = (
863 UniqueConstraint('user_id', 'follows_repository_id'),
862 UniqueConstraint('user_id', 'follows_repository_id'),
864 UniqueConstraint('user_id', 'follows_user_id'),
863 UniqueConstraint('user_id', 'follows_user_id'),
865 {'extend_existing': True, 'mysql_engine': 'InnoDB',
864 {'extend_existing': True, 'mysql_engine': 'InnoDB',
866 'mysql_charset': 'utf8'}
865 'mysql_charset': 'utf8'}
867 )
866 )
868
867
869 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
868 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
870 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
869 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
871 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
870 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
872 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
871 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
873 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
872 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
874
873
875 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
874 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
876
875
877 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
876 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
878 follows_repository = relationship('Repository', order_by='Repository.repo_name')
877 follows_repository = relationship('Repository', order_by='Repository.repo_name')
879
878
880
879
881 class CacheInvalidation(Base, BaseModel):
880 class CacheInvalidation(Base, BaseModel):
882 __tablename__ = 'cache_invalidation'
881 __tablename__ = 'cache_invalidation'
883 __table_args__ = (
882 __table_args__ = (
884 UniqueConstraint('cache_key'),
883 UniqueConstraint('cache_key'),
885 Index('key_idx', 'cache_key'),
884 Index('key_idx', 'cache_key'),
886 {'extend_existing': True, 'mysql_engine': 'InnoDB',
885 {'extend_existing': True, 'mysql_engine': 'InnoDB',
887 'mysql_charset': 'utf8'},
886 'mysql_charset': 'utf8'},
888 )
887 )
889 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
888 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
890 cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None)
889 cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None)
891 cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None)
890 cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None)
892 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
891 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
893
892
894 def __init__(self, cache_key, cache_args=''):
893 def __init__(self, cache_key, cache_args=''):
895 self.cache_key = cache_key
894 self.cache_key = cache_key
896 self.cache_args = cache_args
895 self.cache_args = cache_args
897 self.cache_active = False
896 self.cache_active = False
898
897
899
898
900 class ChangesetComment(Base, BaseModel):
899 class ChangesetComment(Base, BaseModel):
901 __tablename__ = 'changeset_comments'
900 __tablename__ = 'changeset_comments'
902 __table_args__ = (
901 __table_args__ = (
903 Index('cc_revision_idx', 'revision'),
902 Index('cc_revision_idx', 'revision'),
904 {'extend_existing': True, 'mysql_engine': 'InnoDB',
903 {'extend_existing': True, 'mysql_engine': 'InnoDB',
905 'mysql_charset': 'utf8'},
904 'mysql_charset': 'utf8'},
906 )
905 )
907 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
906 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
908 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
907 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
909 revision = Column('revision', String(40), nullable=True)
908 revision = Column('revision', String(40), nullable=True)
910 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
909 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
911 line_no = Column('line_no', Unicode(10), nullable=True)
910 line_no = Column('line_no', Unicode(10), nullable=True)
912 hl_lines = Column('hl_lines', Unicode(512), nullable=True)
911 hl_lines = Column('hl_lines', Unicode(512), nullable=True)
913 f_path = Column('f_path', Unicode(1000), nullable=True)
912 f_path = Column('f_path', Unicode(1000), nullable=True)
914 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
913 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
915 text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False)
914 text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False)
916 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
915 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
917 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
916 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
918
917
919 author = relationship('User', lazy='joined')
918 author = relationship('User', lazy='joined')
920 repo = relationship('Repository')
919 repo = relationship('Repository')
921 status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan")
920 status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan")
922 pull_request = relationship('PullRequest', lazy='joined')
921 pull_request = relationship('PullRequest', lazy='joined')
923
922
924 @classmethod
923 @classmethod
925 def get_users(cls, revision=None, pull_request_id=None):
924 def get_users(cls, revision=None, pull_request_id=None):
926 """
925 """
927 Returns user associated with this ChangesetComment. ie those
926 Returns user associated with this ChangesetComment. ie those
928 who actually commented
927 who actually commented
929
928
930 :param cls:
929 :param cls:
931 :param revision:
930 :param revision:
932 """
931 """
933 q = Session().query(User)\
932 q = Session().query(User)\
934 .join(ChangesetComment.author)
933 .join(ChangesetComment.author)
935 if revision:
934 if revision:
936 q = q.filter(cls.revision == revision)
935 q = q.filter(cls.revision == revision)
937 elif pull_request_id:
936 elif pull_request_id:
938 q = q.filter(cls.pull_request_id == pull_request_id)
937 q = q.filter(cls.pull_request_id == pull_request_id)
939 return q.all()
938 return q.all()
940
939
941
940
942 class ChangesetStatus(Base, BaseModel):
941 class ChangesetStatus(Base, BaseModel):
943 __tablename__ = 'changeset_statuses'
942 __tablename__ = 'changeset_statuses'
944 __table_args__ = (
943 __table_args__ = (
945 Index('cs_revision_idx', 'revision'),
944 Index('cs_revision_idx', 'revision'),
946 Index('cs_version_idx', 'version'),
945 Index('cs_version_idx', 'version'),
947 UniqueConstraint('repo_id', 'revision', 'version'),
946 UniqueConstraint('repo_id', 'revision', 'version'),
948 {'extend_existing': True, 'mysql_engine': 'InnoDB',
947 {'extend_existing': True, 'mysql_engine': 'InnoDB',
949 'mysql_charset': 'utf8'}
948 'mysql_charset': 'utf8'}
950 )
949 )
951 STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed'
950 STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed'
952 STATUS_APPROVED = 'approved'
951 STATUS_APPROVED = 'approved'
953 STATUS_REJECTED = 'rejected'
952 STATUS_REJECTED = 'rejected'
954 STATUS_UNDER_REVIEW = 'under_review'
953 STATUS_UNDER_REVIEW = 'under_review'
955
954
956 STATUSES = [
955 STATUSES = [
957 (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default
956 (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default
958 (STATUS_APPROVED, _("Approved")),
957 (STATUS_APPROVED, _("Approved")),
959 (STATUS_REJECTED, _("Rejected")),
958 (STATUS_REJECTED, _("Rejected")),
960 (STATUS_UNDER_REVIEW, _("Under Review")),
959 (STATUS_UNDER_REVIEW, _("Under Review")),
961 ]
960 ]
962
961
963 changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True)
962 changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True)
964 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
963 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
965 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
964 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
966 revision = Column('revision', String(40), nullable=False)
965 revision = Column('revision', String(40), nullable=False)
967 status = Column('status', String(128), nullable=False, default=DEFAULT)
966 status = Column('status', String(128), nullable=False, default=DEFAULT)
968 changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id'))
967 changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id'))
969 modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
968 modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
970 version = Column('version', Integer(), nullable=False, default=0)
969 version = Column('version', Integer(), nullable=False, default=0)
971 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
970 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
972
971
973 author = relationship('User', lazy='joined')
972 author = relationship('User', lazy='joined')
974 repo = relationship('Repository')
973 repo = relationship('Repository')
975 comment = relationship('ChangesetComment', lazy='joined')
974 comment = relationship('ChangesetComment', lazy='joined')
976 pull_request = relationship('PullRequest', lazy='joined')
975 pull_request = relationship('PullRequest', lazy='joined')
977
976
978
977
979
978
980 class PullRequest(Base, BaseModel):
979 class PullRequest(Base, BaseModel):
981 __tablename__ = 'pull_requests'
980 __tablename__ = 'pull_requests'
982 __table_args__ = (
981 __table_args__ = (
983 {'extend_existing': True, 'mysql_engine': 'InnoDB',
982 {'extend_existing': True, 'mysql_engine': 'InnoDB',
984 'mysql_charset': 'utf8'},
983 'mysql_charset': 'utf8'},
985 )
984 )
986
985
987 STATUS_NEW = u'new'
986 STATUS_NEW = u'new'
988 STATUS_OPEN = u'open'
987 STATUS_OPEN = u'open'
989 STATUS_CLOSED = u'closed'
988 STATUS_CLOSED = u'closed'
990
989
991 pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True)
990 pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True)
992 title = Column('title', Unicode(256), nullable=True)
991 title = Column('title', Unicode(256), nullable=True)
993 description = Column('description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), nullable=True)
992 description = Column('description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), nullable=True)
994 status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW)
993 status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW)
995 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
994 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
996 updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
995 updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
997 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
996 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
998 _revisions = Column('revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql'))
997 _revisions = Column('revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql'))
999 org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
998 org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1000 org_ref = Column('org_ref', Unicode(256), nullable=False)
999 org_ref = Column('org_ref', Unicode(256), nullable=False)
1001 other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1000 other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1002 other_ref = Column('other_ref', Unicode(256), nullable=False)
1001 other_ref = Column('other_ref', Unicode(256), nullable=False)
1003
1002
1004 author = relationship('User', lazy='joined')
1003 author = relationship('User', lazy='joined')
1005 reviewers = relationship('PullRequestReviewers',
1004 reviewers = relationship('PullRequestReviewers',
1006 cascade="all, delete, delete-orphan")
1005 cascade="all, delete, delete-orphan")
1007 org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id')
1006 org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id')
1008 other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id')
1007 other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id')
1009 statuses = relationship('ChangesetStatus')
1008 statuses = relationship('ChangesetStatus')
1010 comments = relationship('ChangesetComment',
1009 comments = relationship('ChangesetComment',
1011 cascade="all, delete, delete-orphan")
1010 cascade="all, delete, delete-orphan")
1012
1011
1013
1012
1014 class PullRequestReviewers(Base, BaseModel):
1013 class PullRequestReviewers(Base, BaseModel):
1015 __tablename__ = 'pull_request_reviewers'
1014 __tablename__ = 'pull_request_reviewers'
1016 __table_args__ = (
1015 __table_args__ = (
1017 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1016 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1018 'mysql_charset': 'utf8'},
1017 'mysql_charset': 'utf8'},
1019 )
1018 )
1020
1019
1021 def __init__(self, user=None, pull_request=None):
1020 def __init__(self, user=None, pull_request=None):
1022 self.user = user
1021 self.user = user
1023 self.pull_request = pull_request
1022 self.pull_request = pull_request
1024
1023
1025 pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True)
1024 pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True)
1026 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False)
1025 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False)
1027 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True)
1026 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True)
1028
1027
1029 user = relationship('User')
1028 user = relationship('User')
1030 pull_request = relationship('PullRequest')
1029 pull_request = relationship('PullRequest')
1031
1030
1032
1031
1033 class Notification(Base, BaseModel):
1032 class Notification(Base, BaseModel):
1034 __tablename__ = 'notifications'
1033 __tablename__ = 'notifications'
1035 __table_args__ = (
1034 __table_args__ = (
1036 Index('notification_type_idx', 'type'),
1035 Index('notification_type_idx', 'type'),
1037 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1036 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1038 'mysql_charset': 'utf8'},
1037 'mysql_charset': 'utf8'},
1039 )
1038 )
1040
1039
1041 TYPE_CHANGESET_COMMENT = u'cs_comment'
1040 TYPE_CHANGESET_COMMENT = u'cs_comment'
1042 TYPE_MESSAGE = u'message'
1041 TYPE_MESSAGE = u'message'
1043 TYPE_MENTION = u'mention'
1042 TYPE_MENTION = u'mention'
1044 TYPE_REGISTRATION = u'registration'
1043 TYPE_REGISTRATION = u'registration'
1045 TYPE_PULL_REQUEST = u'pull_request'
1044 TYPE_PULL_REQUEST = u'pull_request'
1046 TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment'
1045 TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment'
1047
1046
1048 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
1047 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
1049 subject = Column('subject', Unicode(512), nullable=True)
1048 subject = Column('subject', Unicode(512), nullable=True)
1050 body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True)
1049 body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True)
1051 created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
1050 created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
1052 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1051 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1053 type_ = Column('type', Unicode(256))
1052 type_ = Column('type', Unicode(256))
1054
1053
1055 created_by_user = relationship('User')
1054 created_by_user = relationship('User')
1056 notifications_to_users = relationship('UserNotification', lazy='joined',
1055 notifications_to_users = relationship('UserNotification', lazy='joined',
1057 cascade="all, delete, delete-orphan")
1056 cascade="all, delete, delete-orphan")
1058
1057
1059
1058
1060 class UserNotification(Base, BaseModel):
1059 class UserNotification(Base, BaseModel):
1061 __tablename__ = 'user_to_notification'
1060 __tablename__ = 'user_to_notification'
1062 __table_args__ = (
1061 __table_args__ = (
1063 UniqueConstraint('user_id', 'notification_id'),
1062 UniqueConstraint('user_id', 'notification_id'),
1064 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1063 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1065 'mysql_charset': 'utf8'}
1064 'mysql_charset': 'utf8'}
1066 )
1065 )
1067 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
1066 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
1068 notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
1067 notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
1069 read = Column('read', Boolean, default=False)
1068 read = Column('read', Boolean, default=False)
1070 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
1069 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
1071
1070
1072 user = relationship('User', lazy="joined")
1071 user = relationship('User', lazy="joined")
1073 notification = relationship('Notification', lazy="joined",
1072 notification = relationship('Notification', lazy="joined",
1074 order_by=lambda: Notification.created_on.desc(),)
1073 order_by=lambda: Notification.created_on.desc(),)
1075
1074
1076
1075
1077 class DbMigrateVersion(Base, BaseModel):
1076 class DbMigrateVersion(Base, BaseModel):
1078 __tablename__ = 'db_migrate_version'
1077 __tablename__ = 'db_migrate_version'
1079 __table_args__ = (
1078 __table_args__ = (
1080 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1079 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1081 'mysql_charset': 'utf8'},
1080 'mysql_charset': 'utf8'},
1082 )
1081 )
1083 repository_id = Column('repository_id', String(250), primary_key=True)
1082 repository_id = Column('repository_id', String(250), primary_key=True)
1084 repository_path = Column('repository_path', Text)
1083 repository_path = Column('repository_path', Text)
1085 version = Column('version', Integer)
1084 version = Column('version', Integer)
@@ -1,1146 +1,1145 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2019 RhodeCode GmbH
3 # Copyright (C) 2010-2019 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import os
21 import os
22 import time
22 import time
23 import logging
23 import logging
24 import datetime
24 import datetime
25 import traceback
25 import traceback
26 import hashlib
26 import hashlib
27 import collections
27 import collections
28
28
29 from sqlalchemy import *
29 from sqlalchemy import *
30 from sqlalchemy.ext.hybrid import hybrid_property
30 from sqlalchemy.ext.hybrid import hybrid_property
31 from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
31 from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
32 from sqlalchemy.exc import DatabaseError
32 from sqlalchemy.exc import DatabaseError
33 from beaker.cache import cache_region, region_invalidate
33 from beaker.cache import cache_region, region_invalidate
34 from webob.exc import HTTPNotFound
34 from webob.exc import HTTPNotFound
35
35
36 from rhodecode.translation import _
36 from rhodecode.translation import _
37
37
38 from rhodecode.lib.vcs import get_backend
38 from rhodecode.lib.vcs import get_backend
39 from rhodecode.lib.vcs.utils.helpers import get_scm
39 from rhodecode.lib.vcs.utils.helpers import get_scm
40 from rhodecode.lib.vcs.exceptions import VCSError
40 from rhodecode.lib.vcs.exceptions import VCSError
41 from zope.cachedescriptors.property import Lazy as LazyProperty
41 from zope.cachedescriptors.property import Lazy as LazyProperty
42 from rhodecode.lib.vcs.backends.base import EmptyCommit
42 from rhodecode.lib.vcs.backends.base import EmptyCommit
43
43
44 from rhodecode.lib.utils2 import str2bool, safe_str, get_commit_safe, \
44 from rhodecode.lib.utils2 import str2bool, safe_str, get_commit_safe, \
45 safe_unicode, remove_suffix, remove_prefix, time_to_datetime
45 safe_unicode, remove_suffix, remove_prefix, time_to_datetime
46 from rhodecode.lib.ext_json import json
46 from rhodecode.lib.ext_json import json
47 from rhodecode.lib.caching_query import FromCache
47 from rhodecode.lib.caching_query import FromCache
48
48
49 from rhodecode.model.meta import Base, Session
49 from rhodecode.model.meta import Base, Session
50
50
51 URL_SEP = '/'
51 URL_SEP = '/'
52 log = logging.getLogger(__name__)
52 log = logging.getLogger(__name__)
53
53
54 #==============================================================================
54 #==============================================================================
55 # BASE CLASSES
55 # BASE CLASSES
56 #==============================================================================
56 #==============================================================================
57
57
58 _hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest()
58 _hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest()
59
59
60
60
61 class BaseModel(object):
61 class BaseModel(object):
62 """
62 """
63 Base Model for all classes
63 Base Model for all classes
64 """
64 """
65
65
66 @classmethod
66 @classmethod
67 def _get_keys(cls):
67 def _get_keys(cls):
68 """return column names for this model """
68 """return column names for this model """
69 return class_mapper(cls).c.keys()
69 return class_mapper(cls).c.keys()
70
70
71 def get_dict(self):
71 def get_dict(self):
72 """
72 """
73 return dict with keys and values corresponding
73 return dict with keys and values corresponding
74 to this model data """
74 to this model data """
75
75
76 d = {}
76 d = {}
77 for k in self._get_keys():
77 for k in self._get_keys():
78 d[k] = getattr(self, k)
78 d[k] = getattr(self, k)
79
79
80 # also use __json__() if present to get additional fields
80 # also use __json__() if present to get additional fields
81 _json_attr = getattr(self, '__json__', None)
81 _json_attr = getattr(self, '__json__', None)
82 if _json_attr:
82 if _json_attr:
83 # update with attributes from __json__
83 # update with attributes from __json__
84 if callable(_json_attr):
84 if callable(_json_attr):
85 _json_attr = _json_attr()
85 _json_attr = _json_attr()
86 for k, val in _json_attr.iteritems():
86 for k, val in _json_attr.iteritems():
87 d[k] = val
87 d[k] = val
88 return d
88 return d
89
89
90 def get_appstruct(self):
90 def get_appstruct(self):
91 """return list with keys and values tupples corresponding
91 """return list with keys and values tupples corresponding
92 to this model data """
92 to this model data """
93
93
94 l = []
94 l = []
95 for k in self._get_keys():
95 for k in self._get_keys():
96 l.append((k, getattr(self, k),))
96 l.append((k, getattr(self, k),))
97 return l
97 return l
98
98
99 def populate_obj(self, populate_dict):
99 def populate_obj(self, populate_dict):
100 """populate model with data from given populate_dict"""
100 """populate model with data from given populate_dict"""
101
101
102 for k in self._get_keys():
102 for k in self._get_keys():
103 if k in populate_dict:
103 if k in populate_dict:
104 setattr(self, k, populate_dict[k])
104 setattr(self, k, populate_dict[k])
105
105
106 @classmethod
106 @classmethod
107 def query(cls):
107 def query(cls):
108 return Session().query(cls)
108 return Session().query(cls)
109
109
110 @classmethod
110 @classmethod
111 def get(cls, id_):
111 def get(cls, id_):
112 if id_:
112 if id_:
113 return cls.query().get(id_)
113 return cls.query().get(id_)
114
114
115 @classmethod
115 @classmethod
116 def get_or_404(cls, id_):
116 def get_or_404(cls, id_):
117 try:
117 try:
118 id_ = int(id_)
118 id_ = int(id_)
119 except (TypeError, ValueError):
119 except (TypeError, ValueError):
120 raise HTTPNotFound
120 raise HTTPNotFound
121
121
122 res = cls.query().get(id_)
122 res = cls.query().get(id_)
123 if not res:
123 if not res:
124 raise HTTPNotFound
124 raise HTTPNotFound
125 return res
125 return res
126
126
127 @classmethod
127 @classmethod
128 def getAll(cls):
128 def getAll(cls):
129 # deprecated and left for backward compatibility
129 # deprecated and left for backward compatibility
130 return cls.get_all()
130 return cls.get_all()
131
131
132 @classmethod
132 @classmethod
133 def get_all(cls):
133 def get_all(cls):
134 return cls.query().all()
134 return cls.query().all()
135
135
136 @classmethod
136 @classmethod
137 def delete(cls, id_):
137 def delete(cls, id_):
138 obj = cls.query().get(id_)
138 obj = cls.query().get(id_)
139 Session().delete(obj)
139 Session().delete(obj)
140
140
141 def __repr__(self):
141 def __repr__(self):
142 if hasattr(self, '__unicode__'):
142 if hasattr(self, '__unicode__'):
143 # python repr needs to return str
143 # python repr needs to return str
144 return safe_str(self.__unicode__())
144 return safe_str(self.__unicode__())
145 return '<DB:%s>' % (self.__class__.__name__)
145 return '<DB:%s>' % (self.__class__.__name__)
146
146
147
147
148 class RhodeCodeSetting(Base, BaseModel):
148 class RhodeCodeSetting(Base, BaseModel):
149 __tablename__ = 'rhodecode_settings'
149 __tablename__ = 'rhodecode_settings'
150 __table_args__ = (
150 __table_args__ = (
151 UniqueConstraint('app_settings_name'),
151 UniqueConstraint('app_settings_name'),
152 {'extend_existing': True, 'mysql_engine': 'InnoDB',
152 {'extend_existing': True, 'mysql_engine': 'InnoDB',
153 'mysql_charset': 'utf8'}
153 'mysql_charset': 'utf8'}
154 )
154 )
155 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
155 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
156 app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None)
156 app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None)
157 _app_settings_value = Column("app_settings_value", String(255), nullable=True, unique=None, default=None)
157 _app_settings_value = Column("app_settings_value", String(255), nullable=True, unique=None, default=None)
158
158
159 def __init__(self, k='', v=''):
159 def __init__(self, k='', v=''):
160 self.app_settings_name = k
160 self.app_settings_name = k
161 self.app_settings_value = v
161 self.app_settings_value = v
162
162
163 @validates('_app_settings_value')
163 @validates('_app_settings_value')
164 def validate_settings_value(self, key, val):
164 def validate_settings_value(self, key, val):
165 assert type(val) == unicode
165 assert type(val) == unicode
166 return val
166 return val
167
167
168 @hybrid_property
168 @hybrid_property
169 def app_settings_value(self):
169 def app_settings_value(self):
170 v = self._app_settings_value
170 v = self._app_settings_value
171 if self.app_settings_name in ["ldap_active",
171 if self.app_settings_name in ["ldap_active",
172 "default_repo_enable_statistics",
172 "default_repo_enable_statistics",
173 "default_repo_enable_locking",
173 "default_repo_enable_locking",
174 "default_repo_private",
174 "default_repo_private",
175 "default_repo_enable_downloads"]:
175 "default_repo_enable_downloads"]:
176 v = str2bool(v)
176 v = str2bool(v)
177 return v
177 return v
178
178
179 @app_settings_value.setter
179 @app_settings_value.setter
180 def app_settings_value(self, val):
180 def app_settings_value(self, val):
181 """
181 """
182 Setter that will always make sure we use unicode in app_settings_value
182 Setter that will always make sure we use unicode in app_settings_value
183
183
184 :param val:
184 :param val:
185 """
185 """
186 self._app_settings_value = safe_unicode(val)
186 self._app_settings_value = safe_unicode(val)
187
187
188 def __unicode__(self):
188 def __unicode__(self):
189 return u"<%s('%s:%s')>" % (
189 return u"<%s('%s:%s')>" % (
190 self.__class__.__name__,
190 self.__class__.__name__,
191 self.app_settings_name, self.app_settings_value
191 self.app_settings_name, self.app_settings_value
192 )
192 )
193
193
194
194
195 class RhodeCodeUi(Base, BaseModel):
195 class RhodeCodeUi(Base, BaseModel):
196 __tablename__ = 'rhodecode_ui'
196 __tablename__ = 'rhodecode_ui'
197 __table_args__ = (
197 __table_args__ = (
198 UniqueConstraint('ui_key'),
198 UniqueConstraint('ui_key'),
199 {'extend_existing': True, 'mysql_engine': 'InnoDB',
199 {'extend_existing': True, 'mysql_engine': 'InnoDB',
200 'mysql_charset': 'utf8'}
200 'mysql_charset': 'utf8'}
201 )
201 )
202
202
203 HOOK_REPO_SIZE = 'changegroup.repo_size'
203 HOOK_REPO_SIZE = 'changegroup.repo_size'
204 HOOK_PUSH = 'changegroup.push_logger'
204 HOOK_PUSH = 'changegroup.push_logger'
205 HOOK_PRE_PUSH = 'prechangegroup.pre_push'
205 HOOK_PRE_PUSH = 'prechangegroup.pre_push'
206 HOOK_PULL = 'outgoing.pull_logger'
206 HOOK_PULL = 'outgoing.pull_logger'
207 HOOK_PRE_PULL = 'preoutgoing.pre_pull'
207 HOOK_PRE_PULL = 'preoutgoing.pre_pull'
208
208
209 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
209 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
210 ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None)
210 ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None)
211 ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None)
211 ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None)
212 ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None)
212 ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None)
213 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
213 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
214
214
215
215
216
216
217 class User(Base, BaseModel):
217 class User(Base, BaseModel):
218 __tablename__ = 'users'
218 __tablename__ = 'users'
219 __table_args__ = (
219 __table_args__ = (
220 UniqueConstraint('username'), UniqueConstraint('email'),
220 UniqueConstraint('username'), UniqueConstraint('email'),
221 Index('u_username_idx', 'username'),
221 Index('u_username_idx', 'username'),
222 Index('u_email_idx', 'email'),
222 Index('u_email_idx', 'email'),
223 {'extend_existing': True, 'mysql_engine': 'InnoDB',
223 {'extend_existing': True, 'mysql_engine': 'InnoDB',
224 'mysql_charset': 'utf8'}
224 'mysql_charset': 'utf8'}
225 )
225 )
226 DEFAULT_USER = 'default'
226 DEFAULT_USER = 'default'
227
227
228 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
228 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
229 username = Column("username", String(255), nullable=True, unique=None, default=None)
229 username = Column("username", String(255), nullable=True, unique=None, default=None)
230 password = Column("password", String(255), nullable=True, unique=None, default=None)
230 password = Column("password", String(255), nullable=True, unique=None, default=None)
231 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
231 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
232 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
232 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
233 name = Column("firstname", String(255), nullable=True, unique=None, default=None)
233 name = Column("firstname", String(255), nullable=True, unique=None, default=None)
234 lastname = Column("lastname", String(255), nullable=True, unique=None, default=None)
234 lastname = Column("lastname", String(255), nullable=True, unique=None, default=None)
235 _email = Column("email", String(255), nullable=True, unique=None, default=None)
235 _email = Column("email", String(255), nullable=True, unique=None, default=None)
236 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
236 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
237 ldap_dn = Column("ldap_dn", String(255), nullable=True, unique=None, default=None)
237 ldap_dn = Column("ldap_dn", String(255), nullable=True, unique=None, default=None)
238 api_key = Column("api_key", String(255), nullable=True, unique=None, default=None)
238 api_key = Column("api_key", String(255), nullable=True, unique=None, default=None)
239 inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
239 inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
240
240
241 user_log = relationship('UserLog')
241 user_log = relationship('UserLog')
242 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
242 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
243
243
244 repositories = relationship('Repository')
244 repositories = relationship('Repository')
245 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
245 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
246 followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all')
246 followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all')
247
247
248 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
248 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
249 repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all')
249 repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all')
250
250
251 group_member = relationship('UserGroupMember', cascade='all')
251 group_member = relationship('UserGroupMember', cascade='all')
252
252
253 notifications = relationship('UserNotification', cascade='all')
253 notifications = relationship('UserNotification', cascade='all')
254 # notifications assigned to this user
254 # notifications assigned to this user
255 user_created_notifications = relationship('Notification', cascade='all')
255 user_created_notifications = relationship('Notification', cascade='all')
256 # comments created by this user
256 # comments created by this user
257 user_comments = relationship('ChangesetComment', cascade='all')
257 user_comments = relationship('ChangesetComment', cascade='all')
258 user_emails = relationship('UserEmailMap', cascade='all')
258 user_emails = relationship('UserEmailMap', cascade='all')
259
259
260 @hybrid_property
260 @hybrid_property
261 def email(self):
261 def email(self):
262 return self._email
262 return self._email
263
263
264 @email.setter
264 @email.setter
265 def email(self, val):
265 def email(self, val):
266 self._email = val.lower() if val else None
266 self._email = val.lower() if val else None
267
267
268 @property
268 @property
269 def firstname(self):
269 def firstname(self):
270 # alias for future
270 # alias for future
271 return self.name
271 return self.name
272
272
273 @property
273 @property
274 def username_and_name(self):
274 def username_and_name(self):
275 return '%s (%s %s)' % (self.username, self.firstname, self.lastname)
275 return '%s (%s %s)' % (self.username, self.firstname, self.lastname)
276
276
277 @property
277 @property
278 def full_name(self):
278 def full_name(self):
279 return '%s %s' % (self.firstname, self.lastname)
279 return '%s %s' % (self.firstname, self.lastname)
280
280
281 @property
281 @property
282 def full_contact(self):
282 def full_contact(self):
283 return '%s %s <%s>' % (self.firstname, self.lastname, self.email)
283 return '%s %s <%s>' % (self.firstname, self.lastname, self.email)
284
284
285 @property
285 @property
286 def short_contact(self):
286 def short_contact(self):
287 return '%s %s' % (self.firstname, self.lastname)
287 return '%s %s' % (self.firstname, self.lastname)
288
288
289 @property
289 @property
290 def is_admin(self):
290 def is_admin(self):
291 return self.admin
291 return self.admin
292
292
293 @classmethod
293 @classmethod
294 def get_by_username(cls, username, case_insensitive=False, cache=False):
294 def get_by_username(cls, username, case_insensitive=False, cache=False):
295 if case_insensitive:
295 if case_insensitive:
296 q = cls.query().filter(cls.username.ilike(username))
296 q = cls.query().filter(cls.username.ilike(username))
297 else:
297 else:
298 q = cls.query().filter(cls.username == username)
298 q = cls.query().filter(cls.username == username)
299
299
300 if cache:
300 if cache:
301 q = q.options(FromCache(
301 q = q.options(FromCache(
302 "sql_cache_short",
302 "sql_cache_short",
303 "get_user_%s" % _hash_key(username)
303 "get_user_%s" % _hash_key(username)
304 )
304 )
305 )
305 )
306 return q.scalar()
306 return q.scalar()
307
307
308 @classmethod
308 @classmethod
309 def get_by_auth_token(cls, auth_token, cache=False):
309 def get_by_auth_token(cls, auth_token, cache=False):
310 q = cls.query().filter(cls.api_key == auth_token)
310 q = cls.query().filter(cls.api_key == auth_token)
311
311
312 if cache:
312 if cache:
313 q = q.options(FromCache("sql_cache_short",
313 q = q.options(FromCache("sql_cache_short",
314 "get_auth_token_%s" % auth_token))
314 "get_auth_token_%s" % auth_token))
315 return q.scalar()
315 return q.scalar()
316
316
317 @classmethod
317 @classmethod
318 def get_by_email(cls, email, case_insensitive=False, cache=False):
318 def get_by_email(cls, email, case_insensitive=False, cache=False):
319 if case_insensitive:
319 if case_insensitive:
320 q = cls.query().filter(cls.email.ilike(email))
320 q = cls.query().filter(cls.email.ilike(email))
321 else:
321 else:
322 q = cls.query().filter(cls.email == email)
322 q = cls.query().filter(cls.email == email)
323
323
324 if cache:
324 if cache:
325 q = q.options(FromCache("sql_cache_short",
325 q = q.options(FromCache("sql_cache_short",
326 "get_email_key_%s" % email))
326 "get_email_key_%s" % email))
327
327
328 ret = q.scalar()
328 ret = q.scalar()
329 if ret is None:
329 if ret is None:
330 q = UserEmailMap.query()
330 q = UserEmailMap.query()
331 # try fetching in alternate email map
331 # try fetching in alternate email map
332 if case_insensitive:
332 if case_insensitive:
333 q = q.filter(UserEmailMap.email.ilike(email))
333 q = q.filter(UserEmailMap.email.ilike(email))
334 else:
334 else:
335 q = q.filter(UserEmailMap.email == email)
335 q = q.filter(UserEmailMap.email == email)
336 q = q.options(joinedload(UserEmailMap.user))
336 q = q.options(joinedload(UserEmailMap.user))
337 if cache:
337 if cache:
338 q = q.options(FromCache("sql_cache_short",
338 q = q.options(FromCache("sql_cache_short",
339 "get_email_map_key_%s" % email))
339 "get_email_map_key_%s" % email))
340 ret = getattr(q.scalar(), 'user', None)
340 ret = getattr(q.scalar(), 'user', None)
341
341
342 return ret
342 return ret
343
343
344 @classmethod
344 @classmethod
345 def get_first_admin(cls):
345 def get_first_admin(cls):
346 user = User.query().filter(User.admin == True).first()
346 user = User.query().filter(User.admin == True).first()
347 if user is None:
347 if user is None:
348 raise Exception('Missing administrative account!')
348 raise Exception('Missing administrative account!')
349 return user
349 return user
350
350
351 @classmethod
351 @classmethod
352 def get_default_user(cls, cache=False):
352 def get_default_user(cls, cache=False):
353 user = User.get_by_username(User.DEFAULT_USER, cache=cache)
353 user = User.get_by_username(User.DEFAULT_USER, cache=cache)
354 if user is None:
354 if user is None:
355 raise Exception('Missing default account!')
355 raise Exception('Missing default account!')
356 return user
356 return user
357
357
358
358
359
359
360
360
361 class UserEmailMap(Base, BaseModel):
361 class UserEmailMap(Base, BaseModel):
362 __tablename__ = 'user_email_map'
362 __tablename__ = 'user_email_map'
363 __table_args__ = (
363 __table_args__ = (
364 Index('uem_email_idx', 'email'),
364 Index('uem_email_idx', 'email'),
365 UniqueConstraint('email'),
365 UniqueConstraint('email'),
366 {'extend_existing': True, 'mysql_engine': 'InnoDB',
366 {'extend_existing': True, 'mysql_engine': 'InnoDB',
367 'mysql_charset': 'utf8'}
367 'mysql_charset': 'utf8'}
368 )
368 )
369 __mapper_args__ = {}
369 __mapper_args__ = {}
370
370
371 email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
371 email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
372 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
372 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
373 _email = Column("email", String(255), nullable=True, unique=False, default=None)
373 _email = Column("email", String(255), nullable=True, unique=False, default=None)
374 user = relationship('User', lazy='joined')
374 user = relationship('User', lazy='joined')
375
375
376 @validates('_email')
376 @validates('_email')
377 def validate_email(self, key, email):
377 def validate_email(self, key, email):
378 # check if this email is not main one
378 # check if this email is not main one
379 main_email = Session().query(User).filter(User.email == email).scalar()
379 main_email = Session().query(User).filter(User.email == email).scalar()
380 if main_email is not None:
380 if main_email is not None:
381 raise AttributeError('email %s is present is user table' % email)
381 raise AttributeError('email %s is present is user table' % email)
382 return email
382 return email
383
383
384 @hybrid_property
384 @hybrid_property
385 def email(self):
385 def email(self):
386 return self._email
386 return self._email
387
387
388 @email.setter
388 @email.setter
389 def email(self, val):
389 def email(self, val):
390 self._email = val.lower() if val else None
390 self._email = val.lower() if val else None
391
391
392
392
393 class UserIpMap(Base, BaseModel):
393 class UserIpMap(Base, BaseModel):
394 __tablename__ = 'user_ip_map'
394 __tablename__ = 'user_ip_map'
395 __table_args__ = (
395 __table_args__ = (
396 UniqueConstraint('user_id', 'ip_addr'),
396 UniqueConstraint('user_id', 'ip_addr'),
397 {'extend_existing': True, 'mysql_engine': 'InnoDB',
397 {'extend_existing': True, 'mysql_engine': 'InnoDB',
398 'mysql_charset': 'utf8'}
398 'mysql_charset': 'utf8'}
399 )
399 )
400 __mapper_args__ = {}
400 __mapper_args__ = {}
401
401
402 ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
402 ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
403 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
403 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
404 ip_addr = Column("ip_addr", String(255), nullable=True, unique=False, default=None)
404 ip_addr = Column("ip_addr", String(255), nullable=True, unique=False, default=None)
405 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
405 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
406 user = relationship('User', lazy='joined')
406 user = relationship('User', lazy='joined')
407
407
408
408
409 class UserLog(Base, BaseModel):
409 class UserLog(Base, BaseModel):
410 __tablename__ = 'user_logs'
410 __tablename__ = 'user_logs'
411 __table_args__ = (
411 __table_args__ = (
412 {'extend_existing': True, 'mysql_engine': 'InnoDB',
412 {'extend_existing': True, 'mysql_engine': 'InnoDB',
413 'mysql_charset': 'utf8'},
413 'mysql_charset': 'utf8'},
414 )
414 )
415 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
415 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
416 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
416 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
417 username = Column("username", String(255), nullable=True, unique=None, default=None)
417 username = Column("username", String(255), nullable=True, unique=None, default=None)
418 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
418 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
419 repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None)
419 repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None)
420 user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None)
420 user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None)
421 action = Column("action", String(1200000), nullable=True, unique=None, default=None)
421 action = Column("action", String(1200000), nullable=True, unique=None, default=None)
422 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
422 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
423
423
424 def __unicode__(self):
424 def __unicode__(self):
425 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
425 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
426 self.repository_name,
426 self.repository_name,
427 self.action)
427 self.action)
428
428
429 user = relationship('User')
429 user = relationship('User')
430 repository = relationship('Repository', cascade='')
430 repository = relationship('Repository', cascade='')
431
431
432
432
433 class UserGroup(Base, BaseModel):
433 class UserGroup(Base, BaseModel):
434 __tablename__ = 'users_groups'
434 __tablename__ = 'users_groups'
435 __table_args__ = (
435 __table_args__ = (
436 {'extend_existing': True, 'mysql_engine': 'InnoDB',
436 {'extend_existing': True, 'mysql_engine': 'InnoDB',
437 'mysql_charset': 'utf8'},
437 'mysql_charset': 'utf8'},
438 )
438 )
439
439
440 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
440 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
441 users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None)
441 users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None)
442 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
442 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
443 inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
443 inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
444 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
444 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
445
445
446 members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
446 members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
447 users_group_to_perm = relationship('UserGroupToPerm', cascade='all')
447 users_group_to_perm = relationship('UserGroupToPerm', cascade='all')
448 users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
448 users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
449 users_group_repo_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
449 users_group_repo_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
450 user_user_group_to_perm = relationship('UserUserGroupToPerm', cascade='all')
450 user_user_group_to_perm = relationship('UserUserGroupToPerm', cascade='all')
451 user_group_user_group_to_perm = relationship('UserGroupUserGroupToPerm ', primaryjoin="UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id", cascade='all')
451 user_group_user_group_to_perm = relationship('UserGroupUserGroupToPerm ', primaryjoin="UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id", cascade='all')
452
452
453 user = relationship('User')
453 user = relationship('User')
454
454
455 def __unicode__(self):
455 def __unicode__(self):
456 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
456 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
457 self.users_group_id,
457 self.users_group_id,
458 self.users_group_name)
458 self.users_group_name)
459
459
460 @classmethod
460 @classmethod
461 def get_by_group_name(cls, group_name, cache=False,
461 def get_by_group_name(cls, group_name, cache=False,
462 case_insensitive=False):
462 case_insensitive=False):
463 if case_insensitive:
463 if case_insensitive:
464 q = cls.query().filter(cls.users_group_name.ilike(group_name))
464 q = cls.query().filter(cls.users_group_name.ilike(group_name))
465 else:
465 else:
466 q = cls.query().filter(cls.users_group_name == group_name)
466 q = cls.query().filter(cls.users_group_name == group_name)
467 if cache:
467 if cache:
468 q = q.options(FromCache(
468 q = q.options(FromCache(
469 "sql_cache_short",
469 "sql_cache_short",
470 "get_user_%s" % _hash_key(group_name)
470 "get_user_%s" % _hash_key(group_name)
471 )
471 )
472 )
472 )
473 return q.scalar()
473 return q.scalar()
474
474
475 @classmethod
475 @classmethod
476 def get(cls, users_group_id, cache=False):
476 def get(cls, users_group_id, cache=False):
477 user_group = cls.query()
477 user_group = cls.query()
478 if cache:
478 if cache:
479 user_group = user_group.options(FromCache("sql_cache_short",
479 user_group = user_group.options(FromCache("sql_cache_short",
480 "get_users_group_%s" % users_group_id))
480 "get_users_group_%s" % users_group_id))
481 return user_group.get(users_group_id)
481 return user_group.get(users_group_id)
482
482
483
483
484 class UserGroupMember(Base, BaseModel):
484 class UserGroupMember(Base, BaseModel):
485 __tablename__ = 'users_groups_members'
485 __tablename__ = 'users_groups_members'
486 __table_args__ = (
486 __table_args__ = (
487 {'extend_existing': True, 'mysql_engine': 'InnoDB',
487 {'extend_existing': True, 'mysql_engine': 'InnoDB',
488 'mysql_charset': 'utf8'},
488 'mysql_charset': 'utf8'},
489 )
489 )
490
490
491 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
491 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
492 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
492 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
493 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
493 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
494
494
495 user = relationship('User', lazy='joined')
495 user = relationship('User', lazy='joined')
496 users_group = relationship('UserGroup')
496 users_group = relationship('UserGroup')
497
497
498 def __init__(self, gr_id='', u_id=''):
498 def __init__(self, gr_id='', u_id=''):
499 self.users_group_id = gr_id
499 self.users_group_id = gr_id
500 self.user_id = u_id
500 self.user_id = u_id
501
501
502
502
503 class RepositoryField(Base, BaseModel):
503 class RepositoryField(Base, BaseModel):
504 __tablename__ = 'repositories_fields'
504 __tablename__ = 'repositories_fields'
505 __table_args__ = (
505 __table_args__ = (
506 UniqueConstraint('repository_id', 'field_key'), # no-multi field
506 UniqueConstraint('repository_id', 'field_key'), # no-multi field
507 {'extend_existing': True, 'mysql_engine': 'InnoDB',
507 {'extend_existing': True, 'mysql_engine': 'InnoDB',
508 'mysql_charset': 'utf8'},
508 'mysql_charset': 'utf8'},
509 )
509 )
510 PREFIX = 'ex_' # prefix used in form to not conflict with already existing fields
510 PREFIX = 'ex_' # prefix used in form to not conflict with already existing fields
511
511
512 repo_field_id = Column("repo_field_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
512 repo_field_id = Column("repo_field_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
513 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
513 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
514 field_key = Column("field_key", String(250))
514 field_key = Column("field_key", String(250))
515 field_label = Column("field_label", String(1024), nullable=False)
515 field_label = Column("field_label", String(1024), nullable=False)
516 field_value = Column("field_value", String(10000), nullable=False)
516 field_value = Column("field_value", String(10000), nullable=False)
517 field_desc = Column("field_desc", String(1024), nullable=False)
517 field_desc = Column("field_desc", String(1024), nullable=False)
518 field_type = Column("field_type", String(256), nullable=False, unique=None)
518 field_type = Column("field_type", String(256), nullable=False, unique=None)
519 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
519 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
520
520
521 repository = relationship('Repository')
521 repository = relationship('Repository')
522
522
523 @classmethod
523 @classmethod
524 def get_by_key_name(cls, key, repo):
524 def get_by_key_name(cls, key, repo):
525 row = cls.query()\
525 row = cls.query()\
526 .filter(cls.repository == repo)\
526 .filter(cls.repository == repo)\
527 .filter(cls.field_key == key).scalar()
527 .filter(cls.field_key == key).scalar()
528 return row
528 return row
529
529
530
530
531 class Repository(Base, BaseModel):
531 class Repository(Base, BaseModel):
532 __tablename__ = 'repositories'
532 __tablename__ = 'repositories'
533 __table_args__ = (
533 __table_args__ = (
534 UniqueConstraint('repo_name'),
534 UniqueConstraint('repo_name'),
535 Index('r_repo_name_idx', 'repo_name'),
535 Index('r_repo_name_idx', 'repo_name'),
536 {'extend_existing': True, 'mysql_engine': 'InnoDB',
536 {'extend_existing': True, 'mysql_engine': 'InnoDB',
537 'mysql_charset': 'utf8'},
537 'mysql_charset': 'utf8'},
538 )
538 )
539
539
540 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
540 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
541 repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None)
541 repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None)
542 clone_uri = Column("clone_uri", String(255), nullable=True, unique=False, default=None)
542 clone_uri = Column("clone_uri", String(255), nullable=True, unique=False, default=None)
543 repo_type = Column("repo_type", String(255), nullable=False, unique=False, default=None)
543 repo_type = Column("repo_type", String(255), nullable=False, unique=False, default=None)
544 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
544 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
545 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
545 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
546 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
546 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
547 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
547 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
548 description = Column("description", String(10000), nullable=True, unique=None, default=None)
548 description = Column("description", String(10000), nullable=True, unique=None, default=None)
549 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
549 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
550 updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
550 updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
551 landing_rev = Column("landing_revision", String(255), nullable=False, unique=False, default=None)
551 landing_rev = Column("landing_revision", String(255), nullable=False, unique=False, default=None)
552 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
552 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
553 _locked = Column("locked", String(255), nullable=True, unique=False, default=None)
553 _locked = Column("locked", String(255), nullable=True, unique=False, default=None)
554 _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) #JSON data
554 _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) #JSON data
555
555
556 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
556 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
557 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
557 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
558
558
559 user = relationship('User')
559 user = relationship('User')
560 fork = relationship('Repository', remote_side=repo_id)
560 fork = relationship('Repository', remote_side=repo_id)
561 group = relationship('RepoGroup')
561 group = relationship('RepoGroup')
562 repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
562 repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
563 users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
563 users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
564 stats = relationship('Statistics', cascade='all', uselist=False)
564 stats = relationship('Statistics', cascade='all', uselist=False)
565
565
566 followers = relationship('UserFollowing',
566 followers = relationship('UserFollowing',
567 primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id',
567 primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id',
568 cascade='all')
568 cascade='all')
569 extra_fields = relationship('RepositoryField',
569 extra_fields = relationship('RepositoryField',
570 cascade="all, delete, delete-orphan")
570 cascade="all, delete, delete-orphan")
571
571
572 logs = relationship('UserLog')
572 logs = relationship('UserLog')
573 comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan")
573 comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan")
574
574
575 pull_requests_org = relationship('PullRequest',
575 pull_requests_org = relationship('PullRequest',
576 primaryjoin='PullRequest.org_repo_id==Repository.repo_id',
576 primaryjoin='PullRequest.org_repo_id==Repository.repo_id',
577 cascade="all, delete, delete-orphan")
577 cascade="all, delete, delete-orphan")
578
578
579 pull_requests_other = relationship('PullRequest',
579 pull_requests_other = relationship('PullRequest',
580 primaryjoin='PullRequest.other_repo_id==Repository.repo_id',
580 primaryjoin='PullRequest.other_repo_id==Repository.repo_id',
581 cascade="all, delete, delete-orphan")
581 cascade="all, delete, delete-orphan")
582
582
583 def __unicode__(self):
583 def __unicode__(self):
584 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id,
584 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id,
585 safe_unicode(self.repo_name))
585 safe_unicode(self.repo_name))
586
586
587 @classmethod
587 @classmethod
588 def get_by_repo_name(cls, repo_name):
588 def get_by_repo_name(cls, repo_name):
589 q = Session().query(cls).filter(cls.repo_name == repo_name)
589 q = Session().query(cls).filter(cls.repo_name == repo_name)
590 q = q.options(joinedload(Repository.fork))\
590 q = q.options(joinedload(Repository.fork))\
591 .options(joinedload(Repository.user))\
591 .options(joinedload(Repository.user))\
592 .options(joinedload(Repository.group))
592 .options(joinedload(Repository.group))
593 return q.scalar()
593 return q.scalar()
594
594
595
595
596 class RepoGroup(Base, BaseModel):
596 class RepoGroup(Base, BaseModel):
597 __tablename__ = 'groups'
597 __tablename__ = 'groups'
598 __table_args__ = (
598 __table_args__ = (
599 UniqueConstraint('group_name', 'group_parent_id'),
599 UniqueConstraint('group_name', 'group_parent_id'),
600 CheckConstraint('group_id != group_parent_id'),
601 {'extend_existing': True, 'mysql_engine': 'InnoDB',
600 {'extend_existing': True, 'mysql_engine': 'InnoDB',
602 'mysql_charset': 'utf8'},
601 'mysql_charset': 'utf8'},
603 )
602 )
604 __mapper_args__ = {'order_by': 'group_name'}
603 __mapper_args__ = {'order_by': 'group_name'}
605
604
606 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
605 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
607 group_name = Column("group_name", String(255), nullable=False, unique=True, default=None)
606 group_name = Column("group_name", String(255), nullable=False, unique=True, default=None)
608 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
607 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
609 group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None)
608 group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None)
610 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
609 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
611 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
610 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
612
611
613 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
612 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
614 users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
613 users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
615 parent_group = relationship('RepoGroup', remote_side=group_id)
614 parent_group = relationship('RepoGroup', remote_side=group_id)
616 user = relationship('User')
615 user = relationship('User')
617
616
618 def __init__(self, group_name='', parent_group=None):
617 def __init__(self, group_name='', parent_group=None):
619 self.group_name = group_name
618 self.group_name = group_name
620 self.parent_group = parent_group
619 self.parent_group = parent_group
621
620
622 def __unicode__(self):
621 def __unicode__(self):
623 return u"<%s('id:%s:%s')>" % (self.__class__.__name__, self.group_id,
622 return u"<%s('id:%s:%s')>" % (self.__class__.__name__, self.group_id,
624 self.group_name)
623 self.group_name)
625
624
626 @classmethod
625 @classmethod
627 def url_sep(cls):
626 def url_sep(cls):
628 return URL_SEP
627 return URL_SEP
629
628
630 @classmethod
629 @classmethod
631 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
630 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
632 if case_insensitive:
631 if case_insensitive:
633 gr = cls.query()\
632 gr = cls.query()\
634 .filter(cls.group_name.ilike(group_name))
633 .filter(cls.group_name.ilike(group_name))
635 else:
634 else:
636 gr = cls.query()\
635 gr = cls.query()\
637 .filter(cls.group_name == group_name)
636 .filter(cls.group_name == group_name)
638 if cache:
637 if cache:
639 gr = gr.options(FromCache(
638 gr = gr.options(FromCache(
640 "sql_cache_short",
639 "sql_cache_short",
641 "get_group_%s" % _hash_key(group_name)
640 "get_group_%s" % _hash_key(group_name)
642 )
641 )
643 )
642 )
644 return gr.scalar()
643 return gr.scalar()
645
644
646
645
647 class Permission(Base, BaseModel):
646 class Permission(Base, BaseModel):
648 __tablename__ = 'permissions'
647 __tablename__ = 'permissions'
649 __table_args__ = (
648 __table_args__ = (
650 Index('p_perm_name_idx', 'permission_name'),
649 Index('p_perm_name_idx', 'permission_name'),
651 {'extend_existing': True, 'mysql_engine': 'InnoDB',
650 {'extend_existing': True, 'mysql_engine': 'InnoDB',
652 'mysql_charset': 'utf8'},
651 'mysql_charset': 'utf8'},
653 )
652 )
654 PERMS = [
653 PERMS = [
655 ('hg.admin', _('RhodeCode Administrator')),
654 ('hg.admin', _('RhodeCode Administrator')),
656
655
657 ('repository.none', _('Repository no access')),
656 ('repository.none', _('Repository no access')),
658 ('repository.read', _('Repository read access')),
657 ('repository.read', _('Repository read access')),
659 ('repository.write', _('Repository write access')),
658 ('repository.write', _('Repository write access')),
660 ('repository.admin', _('Repository admin access')),
659 ('repository.admin', _('Repository admin access')),
661
660
662 ('group.none', _('Repository group no access')),
661 ('group.none', _('Repository group no access')),
663 ('group.read', _('Repository group read access')),
662 ('group.read', _('Repository group read access')),
664 ('group.write', _('Repository group write access')),
663 ('group.write', _('Repository group write access')),
665 ('group.admin', _('Repository group admin access')),
664 ('group.admin', _('Repository group admin access')),
666
665
667 ('usergroup.none', _('User group no access')),
666 ('usergroup.none', _('User group no access')),
668 ('usergroup.read', _('User group read access')),
667 ('usergroup.read', _('User group read access')),
669 ('usergroup.write', _('User group write access')),
668 ('usergroup.write', _('User group write access')),
670 ('usergroup.admin', _('User group admin access')),
669 ('usergroup.admin', _('User group admin access')),
671
670
672 ('hg.repogroup.create.false', _('Repository Group creation disabled')),
671 ('hg.repogroup.create.false', _('Repository Group creation disabled')),
673 ('hg.repogroup.create.true', _('Repository Group creation enabled')),
672 ('hg.repogroup.create.true', _('Repository Group creation enabled')),
674
673
675 ('hg.usergroup.create.false', _('User Group creation disabled')),
674 ('hg.usergroup.create.false', _('User Group creation disabled')),
676 ('hg.usergroup.create.true', _('User Group creation enabled')),
675 ('hg.usergroup.create.true', _('User Group creation enabled')),
677
676
678 ('hg.create.none', _('Repository creation disabled')),
677 ('hg.create.none', _('Repository creation disabled')),
679 ('hg.create.repository', _('Repository creation enabled')),
678 ('hg.create.repository', _('Repository creation enabled')),
680
679
681 ('hg.fork.none', _('Repository forking disabled')),
680 ('hg.fork.none', _('Repository forking disabled')),
682 ('hg.fork.repository', _('Repository forking enabled')),
681 ('hg.fork.repository', _('Repository forking enabled')),
683
682
684 ('hg.register.none', _('Registration disabled')),
683 ('hg.register.none', _('Registration disabled')),
685 ('hg.register.manual_activate', _('User Registration with manual account activation')),
684 ('hg.register.manual_activate', _('User Registration with manual account activation')),
686 ('hg.register.auto_activate', _('User Registration with automatic account activation')),
685 ('hg.register.auto_activate', _('User Registration with automatic account activation')),
687
686
688 ('hg.extern_activate.manual', _('Manual activation of external account')),
687 ('hg.extern_activate.manual', _('Manual activation of external account')),
689 ('hg.extern_activate.auto', _('Automatic activation of external account')),
688 ('hg.extern_activate.auto', _('Automatic activation of external account')),
690
689
691 ]
690 ]
692
691
693 #definition of system default permissions for DEFAULT user
692 #definition of system default permissions for DEFAULT user
694 DEFAULT_USER_PERMISSIONS = [
693 DEFAULT_USER_PERMISSIONS = [
695 'repository.read',
694 'repository.read',
696 'group.read',
695 'group.read',
697 'usergroup.read',
696 'usergroup.read',
698 'hg.create.repository',
697 'hg.create.repository',
699 'hg.fork.repository',
698 'hg.fork.repository',
700 'hg.register.manual_activate',
699 'hg.register.manual_activate',
701 'hg.extern_activate.auto',
700 'hg.extern_activate.auto',
702 ]
701 ]
703
702
704 # defines which permissions are more important higher the more important
703 # defines which permissions are more important higher the more important
705 # Weight defines which permissions are more important.
704 # Weight defines which permissions are more important.
706 # The higher number the more important.
705 # The higher number the more important.
707 PERM_WEIGHTS = {
706 PERM_WEIGHTS = {
708 'repository.none': 0,
707 'repository.none': 0,
709 'repository.read': 1,
708 'repository.read': 1,
710 'repository.write': 3,
709 'repository.write': 3,
711 'repository.admin': 4,
710 'repository.admin': 4,
712
711
713 'group.none': 0,
712 'group.none': 0,
714 'group.read': 1,
713 'group.read': 1,
715 'group.write': 3,
714 'group.write': 3,
716 'group.admin': 4,
715 'group.admin': 4,
717
716
718 'usergroup.none': 0,
717 'usergroup.none': 0,
719 'usergroup.read': 1,
718 'usergroup.read': 1,
720 'usergroup.write': 3,
719 'usergroup.write': 3,
721 'usergroup.admin': 4,
720 'usergroup.admin': 4,
722 'hg.repogroup.create.false': 0,
721 'hg.repogroup.create.false': 0,
723 'hg.repogroup.create.true': 1,
722 'hg.repogroup.create.true': 1,
724
723
725 'hg.usergroup.create.false': 0,
724 'hg.usergroup.create.false': 0,
726 'hg.usergroup.create.true': 1,
725 'hg.usergroup.create.true': 1,
727
726
728 'hg.fork.none': 0,
727 'hg.fork.none': 0,
729 'hg.fork.repository': 1,
728 'hg.fork.repository': 1,
730 'hg.create.none': 0,
729 'hg.create.none': 0,
731 'hg.create.repository': 1
730 'hg.create.repository': 1
732 }
731 }
733
732
734 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
733 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
735 permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None)
734 permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None)
736 permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None)
735 permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None)
737
736
738 def __unicode__(self):
737 def __unicode__(self):
739 return u"<%s('%s:%s')>" % (
738 return u"<%s('%s:%s')>" % (
740 self.__class__.__name__, self.permission_id, self.permission_name
739 self.__class__.__name__, self.permission_id, self.permission_name
741 )
740 )
742
741
743 @classmethod
742 @classmethod
744 def get_by_key(cls, key):
743 def get_by_key(cls, key):
745 return cls.query().filter(cls.permission_name == key).scalar()
744 return cls.query().filter(cls.permission_name == key).scalar()
746
745
747
746
748 class UserRepoToPerm(Base, BaseModel):
747 class UserRepoToPerm(Base, BaseModel):
749 __tablename__ = 'repo_to_perm'
748 __tablename__ = 'repo_to_perm'
750 __table_args__ = (
749 __table_args__ = (
751 UniqueConstraint('user_id', 'repository_id', 'permission_id'),
750 UniqueConstraint('user_id', 'repository_id', 'permission_id'),
752 {'extend_existing': True, 'mysql_engine': 'InnoDB',
751 {'extend_existing': True, 'mysql_engine': 'InnoDB',
753 'mysql_charset': 'utf8'}
752 'mysql_charset': 'utf8'}
754 )
753 )
755 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
754 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
756 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
755 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
757 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
756 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
758 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
757 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
759
758
760 user = relationship('User')
759 user = relationship('User')
761 repository = relationship('Repository')
760 repository = relationship('Repository')
762 permission = relationship('Permission')
761 permission = relationship('Permission')
763
762
764 def __unicode__(self):
763 def __unicode__(self):
765 return u'<%s => %s >' % (self.user, self.repository)
764 return u'<%s => %s >' % (self.user, self.repository)
766
765
767
766
768 class UserUserGroupToPerm(Base, BaseModel):
767 class UserUserGroupToPerm(Base, BaseModel):
769 __tablename__ = 'user_user_group_to_perm'
768 __tablename__ = 'user_user_group_to_perm'
770 __table_args__ = (
769 __table_args__ = (
771 UniqueConstraint('user_id', 'user_group_id', 'permission_id'),
770 UniqueConstraint('user_id', 'user_group_id', 'permission_id'),
772 {'extend_existing': True, 'mysql_engine': 'InnoDB',
771 {'extend_existing': True, 'mysql_engine': 'InnoDB',
773 'mysql_charset': 'utf8'}
772 'mysql_charset': 'utf8'}
774 )
773 )
775 user_user_group_to_perm_id = Column("user_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
774 user_user_group_to_perm_id = Column("user_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
776 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
775 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
777 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
776 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
778 user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
777 user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
779
778
780 user = relationship('User')
779 user = relationship('User')
781 user_group = relationship('UserGroup')
780 user_group = relationship('UserGroup')
782 permission = relationship('Permission')
781 permission = relationship('Permission')
783
782
784 def __unicode__(self):
783 def __unicode__(self):
785 return u'<%s => %s >' % (self.user, self.user_group)
784 return u'<%s => %s >' % (self.user, self.user_group)
786
785
787
786
788 class UserToPerm(Base, BaseModel):
787 class UserToPerm(Base, BaseModel):
789 __tablename__ = 'user_to_perm'
788 __tablename__ = 'user_to_perm'
790 __table_args__ = (
789 __table_args__ = (
791 UniqueConstraint('user_id', 'permission_id'),
790 UniqueConstraint('user_id', 'permission_id'),
792 {'extend_existing': True, 'mysql_engine': 'InnoDB',
791 {'extend_existing': True, 'mysql_engine': 'InnoDB',
793 'mysql_charset': 'utf8'}
792 'mysql_charset': 'utf8'}
794 )
793 )
795 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
794 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
796 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
795 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
797 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
796 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
798
797
799 user = relationship('User')
798 user = relationship('User')
800 permission = relationship('Permission', lazy='joined')
799 permission = relationship('Permission', lazy='joined')
801
800
802 def __unicode__(self):
801 def __unicode__(self):
803 return u'<%s => %s >' % (self.user, self.permission)
802 return u'<%s => %s >' % (self.user, self.permission)
804
803
805
804
806 class UserGroupRepoToPerm(Base, BaseModel):
805 class UserGroupRepoToPerm(Base, BaseModel):
807 __tablename__ = 'users_group_repo_to_perm'
806 __tablename__ = 'users_group_repo_to_perm'
808 __table_args__ = (
807 __table_args__ = (
809 UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
808 UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
810 {'extend_existing': True, 'mysql_engine': 'InnoDB',
809 {'extend_existing': True, 'mysql_engine': 'InnoDB',
811 'mysql_charset': 'utf8'}
810 'mysql_charset': 'utf8'}
812 )
811 )
813 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
812 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
814 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
813 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
815 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
814 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
816 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
815 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
817
816
818 users_group = relationship('UserGroup')
817 users_group = relationship('UserGroup')
819 permission = relationship('Permission')
818 permission = relationship('Permission')
820 repository = relationship('Repository')
819 repository = relationship('Repository')
821
820
822 def __unicode__(self):
821 def __unicode__(self):
823 return u'<UserGroupRepoToPerm:%s => %s >' % (self.users_group, self.repository)
822 return u'<UserGroupRepoToPerm:%s => %s >' % (self.users_group, self.repository)
824
823
825
824
826 class UserGroupUserGroupToPerm(Base, BaseModel):
825 class UserGroupUserGroupToPerm(Base, BaseModel):
827 __tablename__ = 'user_group_user_group_to_perm'
826 __tablename__ = 'user_group_user_group_to_perm'
828 __table_args__ = (
827 __table_args__ = (
829 UniqueConstraint('target_user_group_id', 'user_group_id', 'permission_id'),
828 UniqueConstraint('target_user_group_id', 'user_group_id', 'permission_id'),
830 CheckConstraint('target_user_group_id != user_group_id'),
829 CheckConstraint('target_user_group_id != user_group_id'),
831 {'extend_existing': True, 'mysql_engine': 'InnoDB',
830 {'extend_existing': True, 'mysql_engine': 'InnoDB',
832 'mysql_charset': 'utf8'}
831 'mysql_charset': 'utf8'}
833 )
832 )
834 user_group_user_group_to_perm_id = Column("user_group_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
833 user_group_user_group_to_perm_id = Column("user_group_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
835 target_user_group_id = Column("target_user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
834 target_user_group_id = Column("target_user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
836 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
835 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
837 user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
836 user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
838
837
839 target_user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id')
838 target_user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id')
840 user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.user_group_id==UserGroup.users_group_id')
839 user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.user_group_id==UserGroup.users_group_id')
841 permission = relationship('Permission')
840 permission = relationship('Permission')
842
841
843 def __unicode__(self):
842 def __unicode__(self):
844 return u'<UserGroupUserGroup:%s => %s >' % (self.target_user_group, self.user_group)
843 return u'<UserGroupUserGroup:%s => %s >' % (self.target_user_group, self.user_group)
845
844
846
845
847 class UserGroupToPerm(Base, BaseModel):
846 class UserGroupToPerm(Base, BaseModel):
848 __tablename__ = 'users_group_to_perm'
847 __tablename__ = 'users_group_to_perm'
849 __table_args__ = (
848 __table_args__ = (
850 UniqueConstraint('users_group_id', 'permission_id',),
849 UniqueConstraint('users_group_id', 'permission_id',),
851 {'extend_existing': True, 'mysql_engine': 'InnoDB',
850 {'extend_existing': True, 'mysql_engine': 'InnoDB',
852 'mysql_charset': 'utf8'}
851 'mysql_charset': 'utf8'}
853 )
852 )
854 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
853 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
855 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
854 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
856 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
855 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
857
856
858 users_group = relationship('UserGroup')
857 users_group = relationship('UserGroup')
859 permission = relationship('Permission')
858 permission = relationship('Permission')
860
859
861
860
862 class UserRepoGroupToPerm(Base, BaseModel):
861 class UserRepoGroupToPerm(Base, BaseModel):
863 __tablename__ = 'user_repo_group_to_perm'
862 __tablename__ = 'user_repo_group_to_perm'
864 __table_args__ = (
863 __table_args__ = (
865 UniqueConstraint('user_id', 'group_id', 'permission_id'),
864 UniqueConstraint('user_id', 'group_id', 'permission_id'),
866 {'extend_existing': True, 'mysql_engine': 'InnoDB',
865 {'extend_existing': True, 'mysql_engine': 'InnoDB',
867 'mysql_charset': 'utf8'}
866 'mysql_charset': 'utf8'}
868 )
867 )
869
868
870 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
869 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
871 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
870 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
872 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
871 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
873 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
872 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
874
873
875 user = relationship('User')
874 user = relationship('User')
876 group = relationship('RepoGroup')
875 group = relationship('RepoGroup')
877 permission = relationship('Permission')
876 permission = relationship('Permission')
878
877
879
878
880 class UserGroupRepoGroupToPerm(Base, BaseModel):
879 class UserGroupRepoGroupToPerm(Base, BaseModel):
881 __tablename__ = 'users_group_repo_group_to_perm'
880 __tablename__ = 'users_group_repo_group_to_perm'
882 __table_args__ = (
881 __table_args__ = (
883 UniqueConstraint('users_group_id', 'group_id'),
882 UniqueConstraint('users_group_id', 'group_id'),
884 {'extend_existing': True, 'mysql_engine': 'InnoDB',
883 {'extend_existing': True, 'mysql_engine': 'InnoDB',
885 'mysql_charset': 'utf8'}
884 'mysql_charset': 'utf8'}
886 )
885 )
887
886
888 users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
887 users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
889 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
888 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
890 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
889 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
891 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
890 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
892
891
893 users_group = relationship('UserGroup')
892 users_group = relationship('UserGroup')
894 permission = relationship('Permission')
893 permission = relationship('Permission')
895 group = relationship('RepoGroup')
894 group = relationship('RepoGroup')
896
895
897
896
898 class Statistics(Base, BaseModel):
897 class Statistics(Base, BaseModel):
899 __tablename__ = 'statistics'
898 __tablename__ = 'statistics'
900 __table_args__ = (
899 __table_args__ = (
901 UniqueConstraint('repository_id'),
900 UniqueConstraint('repository_id'),
902 {'extend_existing': True, 'mysql_engine': 'InnoDB',
901 {'extend_existing': True, 'mysql_engine': 'InnoDB',
903 'mysql_charset': 'utf8'}
902 'mysql_charset': 'utf8'}
904 )
903 )
905 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
904 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
906 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
905 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
907 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
906 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
908 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
907 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
909 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
908 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
910 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
909 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
911
910
912 repository = relationship('Repository', single_parent=True)
911 repository = relationship('Repository', single_parent=True)
913
912
914
913
915 class UserFollowing(Base, BaseModel):
914 class UserFollowing(Base, BaseModel):
916 __tablename__ = 'user_followings'
915 __tablename__ = 'user_followings'
917 __table_args__ = (
916 __table_args__ = (
918 UniqueConstraint('user_id', 'follows_repository_id'),
917 UniqueConstraint('user_id', 'follows_repository_id'),
919 UniqueConstraint('user_id', 'follows_user_id'),
918 UniqueConstraint('user_id', 'follows_user_id'),
920 {'extend_existing': True, 'mysql_engine': 'InnoDB',
919 {'extend_existing': True, 'mysql_engine': 'InnoDB',
921 'mysql_charset': 'utf8'}
920 'mysql_charset': 'utf8'}
922 )
921 )
923
922
924 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
923 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
925 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
924 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
926 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
925 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
927 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
926 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
928 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
927 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
929
928
930 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
929 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
931
930
932 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
931 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
933 follows_repository = relationship('Repository', order_by='Repository.repo_name')
932 follows_repository = relationship('Repository', order_by='Repository.repo_name')
934
933
935
934
936 class CacheInvalidation(Base, BaseModel):
935 class CacheInvalidation(Base, BaseModel):
937 __tablename__ = 'cache_invalidation'
936 __tablename__ = 'cache_invalidation'
938 __table_args__ = (
937 __table_args__ = (
939 UniqueConstraint('cache_key'),
938 UniqueConstraint('cache_key'),
940 Index('key_idx', 'cache_key'),
939 Index('key_idx', 'cache_key'),
941 {'extend_existing': True, 'mysql_engine': 'InnoDB',
940 {'extend_existing': True, 'mysql_engine': 'InnoDB',
942 'mysql_charset': 'utf8'},
941 'mysql_charset': 'utf8'},
943 )
942 )
944 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
943 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
945 cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None)
944 cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None)
946 cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None)
945 cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None)
947 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
946 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
948
947
949 def __init__(self, cache_key, cache_args=''):
948 def __init__(self, cache_key, cache_args=''):
950 self.cache_key = cache_key
949 self.cache_key = cache_key
951 self.cache_args = cache_args
950 self.cache_args = cache_args
952 self.cache_active = False
951 self.cache_active = False
953
952
954
953
955 class ChangesetComment(Base, BaseModel):
954 class ChangesetComment(Base, BaseModel):
956 __tablename__ = 'changeset_comments'
955 __tablename__ = 'changeset_comments'
957 __table_args__ = (
956 __table_args__ = (
958 Index('cc_revision_idx', 'revision'),
957 Index('cc_revision_idx', 'revision'),
959 {'extend_existing': True, 'mysql_engine': 'InnoDB',
958 {'extend_existing': True, 'mysql_engine': 'InnoDB',
960 'mysql_charset': 'utf8'},
959 'mysql_charset': 'utf8'},
961 )
960 )
962 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
961 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
963 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
962 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
964 revision = Column('revision', String(40), nullable=True)
963 revision = Column('revision', String(40), nullable=True)
965 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
964 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
966 line_no = Column('line_no', Unicode(10), nullable=True)
965 line_no = Column('line_no', Unicode(10), nullable=True)
967 hl_lines = Column('hl_lines', Unicode(512), nullable=True)
966 hl_lines = Column('hl_lines', Unicode(512), nullable=True)
968 f_path = Column('f_path', Unicode(1000), nullable=True)
967 f_path = Column('f_path', Unicode(1000), nullable=True)
969 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
968 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
970 text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False)
969 text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False)
971 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
970 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
972 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
971 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
973
972
974 author = relationship('User', lazy='joined')
973 author = relationship('User', lazy='joined')
975 repo = relationship('Repository')
974 repo = relationship('Repository')
976 status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan")
975 status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan")
977 pull_request = relationship('PullRequest', lazy='joined')
976 pull_request = relationship('PullRequest', lazy='joined')
978
977
979
978
980 class ChangesetStatus(Base, BaseModel):
979 class ChangesetStatus(Base, BaseModel):
981 __tablename__ = 'changeset_statuses'
980 __tablename__ = 'changeset_statuses'
982 __table_args__ = (
981 __table_args__ = (
983 Index('cs_revision_idx', 'revision'),
982 Index('cs_revision_idx', 'revision'),
984 Index('cs_version_idx', 'version'),
983 Index('cs_version_idx', 'version'),
985 UniqueConstraint('repo_id', 'revision', 'version'),
984 UniqueConstraint('repo_id', 'revision', 'version'),
986 {'extend_existing': True, 'mysql_engine': 'InnoDB',
985 {'extend_existing': True, 'mysql_engine': 'InnoDB',
987 'mysql_charset': 'utf8'}
986 'mysql_charset': 'utf8'}
988 )
987 )
989 STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed'
988 STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed'
990 STATUS_APPROVED = 'approved'
989 STATUS_APPROVED = 'approved'
991 STATUS_REJECTED = 'rejected'
990 STATUS_REJECTED = 'rejected'
992 STATUS_UNDER_REVIEW = 'under_review'
991 STATUS_UNDER_REVIEW = 'under_review'
993
992
994 STATUSES = [
993 STATUSES = [
995 (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default
994 (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default
996 (STATUS_APPROVED, _("Approved")),
995 (STATUS_APPROVED, _("Approved")),
997 (STATUS_REJECTED, _("Rejected")),
996 (STATUS_REJECTED, _("Rejected")),
998 (STATUS_UNDER_REVIEW, _("Under Review")),
997 (STATUS_UNDER_REVIEW, _("Under Review")),
999 ]
998 ]
1000
999
1001 changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True)
1000 changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True)
1002 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1001 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1003 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1002 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1004 revision = Column('revision', String(40), nullable=False)
1003 revision = Column('revision', String(40), nullable=False)
1005 status = Column('status', String(128), nullable=False, default=DEFAULT)
1004 status = Column('status', String(128), nullable=False, default=DEFAULT)
1006 changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id'))
1005 changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id'))
1007 modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
1006 modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
1008 version = Column('version', Integer(), nullable=False, default=0)
1007 version = Column('version', Integer(), nullable=False, default=0)
1009 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
1008 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
1010
1009
1011 author = relationship('User', lazy='joined')
1010 author = relationship('User', lazy='joined')
1012 repo = relationship('Repository')
1011 repo = relationship('Repository')
1013 comment = relationship('ChangesetComment', lazy='joined')
1012 comment = relationship('ChangesetComment', lazy='joined')
1014 pull_request = relationship('PullRequest', lazy='joined')
1013 pull_request = relationship('PullRequest', lazy='joined')
1015
1014
1016
1015
1017
1016
1018 class PullRequest(Base, BaseModel):
1017 class PullRequest(Base, BaseModel):
1019 __tablename__ = 'pull_requests'
1018 __tablename__ = 'pull_requests'
1020 __table_args__ = (
1019 __table_args__ = (
1021 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1020 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1022 'mysql_charset': 'utf8'},
1021 'mysql_charset': 'utf8'},
1023 )
1022 )
1024
1023
1025 STATUS_NEW = u'new'
1024 STATUS_NEW = u'new'
1026 STATUS_OPEN = u'open'
1025 STATUS_OPEN = u'open'
1027 STATUS_CLOSED = u'closed'
1026 STATUS_CLOSED = u'closed'
1028
1027
1029 pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True)
1028 pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True)
1030 title = Column('title', Unicode(256), nullable=True)
1029 title = Column('title', Unicode(256), nullable=True)
1031 description = Column('description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), nullable=True)
1030 description = Column('description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), nullable=True)
1032 status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW)
1031 status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW)
1033 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1032 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1034 updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1033 updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1035 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1034 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1036 _revisions = Column('revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql'))
1035 _revisions = Column('revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql'))
1037 org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1036 org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1038 org_ref = Column('org_ref', Unicode(256), nullable=False)
1037 org_ref = Column('org_ref', Unicode(256), nullable=False)
1039 other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1038 other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1040 other_ref = Column('other_ref', Unicode(256), nullable=False)
1039 other_ref = Column('other_ref', Unicode(256), nullable=False)
1041
1040
1042 author = relationship('User', lazy='joined')
1041 author = relationship('User', lazy='joined')
1043 reviewers = relationship('PullRequestReviewers',
1042 reviewers = relationship('PullRequestReviewers',
1044 cascade="all, delete, delete-orphan")
1043 cascade="all, delete, delete-orphan")
1045 org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id')
1044 org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id')
1046 other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id')
1045 other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id')
1047 statuses = relationship('ChangesetStatus')
1046 statuses = relationship('ChangesetStatus')
1048 comments = relationship('ChangesetComment',
1047 comments = relationship('ChangesetComment',
1049 cascade="all, delete, delete-orphan")
1048 cascade="all, delete, delete-orphan")
1050
1049
1051
1050
1052 class PullRequestReviewers(Base, BaseModel):
1051 class PullRequestReviewers(Base, BaseModel):
1053 __tablename__ = 'pull_request_reviewers'
1052 __tablename__ = 'pull_request_reviewers'
1054 __table_args__ = (
1053 __table_args__ = (
1055 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1054 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1056 'mysql_charset': 'utf8'},
1055 'mysql_charset': 'utf8'},
1057 )
1056 )
1058
1057
1059 def __init__(self, user=None, pull_request=None):
1058 def __init__(self, user=None, pull_request=None):
1060 self.user = user
1059 self.user = user
1061 self.pull_request = pull_request
1060 self.pull_request = pull_request
1062
1061
1063 pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True)
1062 pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True)
1064 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False)
1063 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False)
1065 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True)
1064 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True)
1066
1065
1067 user = relationship('User')
1066 user = relationship('User')
1068 pull_request = relationship('PullRequest')
1067 pull_request = relationship('PullRequest')
1069
1068
1070
1069
1071 class Notification(Base, BaseModel):
1070 class Notification(Base, BaseModel):
1072 __tablename__ = 'notifications'
1071 __tablename__ = 'notifications'
1073 __table_args__ = (
1072 __table_args__ = (
1074 Index('notification_type_idx', 'type'),
1073 Index('notification_type_idx', 'type'),
1075 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1074 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1076 'mysql_charset': 'utf8'},
1075 'mysql_charset': 'utf8'},
1077 )
1076 )
1078
1077
1079 TYPE_CHANGESET_COMMENT = u'cs_comment'
1078 TYPE_CHANGESET_COMMENT = u'cs_comment'
1080 TYPE_MESSAGE = u'message'
1079 TYPE_MESSAGE = u'message'
1081 TYPE_MENTION = u'mention'
1080 TYPE_MENTION = u'mention'
1082 TYPE_REGISTRATION = u'registration'
1081 TYPE_REGISTRATION = u'registration'
1083 TYPE_PULL_REQUEST = u'pull_request'
1082 TYPE_PULL_REQUEST = u'pull_request'
1084 TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment'
1083 TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment'
1085
1084
1086 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
1085 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
1087 subject = Column('subject', Unicode(512), nullable=True)
1086 subject = Column('subject', Unicode(512), nullable=True)
1088 body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True)
1087 body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True)
1089 created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
1088 created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
1090 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1089 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1091 type_ = Column('type', Unicode(256))
1090 type_ = Column('type', Unicode(256))
1092
1091
1093 created_by_user = relationship('User')
1092 created_by_user = relationship('User')
1094 notifications_to_users = relationship('UserNotification', lazy='joined',
1093 notifications_to_users = relationship('UserNotification', lazy='joined',
1095 cascade="all, delete, delete-orphan")
1094 cascade="all, delete, delete-orphan")
1096
1095
1097
1096
1098 class UserNotification(Base, BaseModel):
1097 class UserNotification(Base, BaseModel):
1099 __tablename__ = 'user_to_notification'
1098 __tablename__ = 'user_to_notification'
1100 __table_args__ = (
1099 __table_args__ = (
1101 UniqueConstraint('user_id', 'notification_id'),
1100 UniqueConstraint('user_id', 'notification_id'),
1102 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1101 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1103 'mysql_charset': 'utf8'}
1102 'mysql_charset': 'utf8'}
1104 )
1103 )
1105 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
1104 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
1106 notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
1105 notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
1107 read = Column('read', Boolean, default=False)
1106 read = Column('read', Boolean, default=False)
1108 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
1107 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
1109
1108
1110 user = relationship('User', lazy="joined")
1109 user = relationship('User', lazy="joined")
1111 notification = relationship('Notification', lazy="joined",
1110 notification = relationship('Notification', lazy="joined",
1112 order_by=lambda: Notification.created_on.desc(),)
1111 order_by=lambda: Notification.created_on.desc(),)
1113
1112
1114
1113
1115 class Gist(Base, BaseModel):
1114 class Gist(Base, BaseModel):
1116 __tablename__ = 'gists'
1115 __tablename__ = 'gists'
1117 __table_args__ = (
1116 __table_args__ = (
1118 Index('g_gist_access_id_idx', 'gist_access_id'),
1117 Index('g_gist_access_id_idx', 'gist_access_id'),
1119 Index('g_created_on_idx', 'created_on'),
1118 Index('g_created_on_idx', 'created_on'),
1120 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1119 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1121 'mysql_charset': 'utf8'}
1120 'mysql_charset': 'utf8'}
1122 )
1121 )
1123 GIST_PUBLIC = u'public'
1122 GIST_PUBLIC = u'public'
1124 GIST_PRIVATE = u'private'
1123 GIST_PRIVATE = u'private'
1125
1124
1126 gist_id = Column('gist_id', Integer(), primary_key=True)
1125 gist_id = Column('gist_id', Integer(), primary_key=True)
1127 gist_access_id = Column('gist_access_id', Unicode(250))
1126 gist_access_id = Column('gist_access_id', Unicode(250))
1128 gist_description = Column('gist_description', UnicodeText().with_variant(UnicodeText(1024), 'mysql'))
1127 gist_description = Column('gist_description', UnicodeText().with_variant(UnicodeText(1024), 'mysql'))
1129 gist_owner = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=True)
1128 gist_owner = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=True)
1130 gist_expires = Column('gist_expires', Float(), nullable=False)
1129 gist_expires = Column('gist_expires', Float(), nullable=False)
1131 gist_type = Column('gist_type', Unicode(128), nullable=False)
1130 gist_type = Column('gist_type', Unicode(128), nullable=False)
1132 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1131 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1133 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1132 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1134
1133
1135 owner = relationship('User')
1134 owner = relationship('User')
1136
1135
1137
1136
1138 class DbMigrateVersion(Base, BaseModel):
1137 class DbMigrateVersion(Base, BaseModel):
1139 __tablename__ = 'db_migrate_version'
1138 __tablename__ = 'db_migrate_version'
1140 __table_args__ = (
1139 __table_args__ = (
1141 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1140 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1142 'mysql_charset': 'utf8'},
1141 'mysql_charset': 'utf8'},
1143 )
1142 )
1144 repository_id = Column('repository_id', String(250), primary_key=True)
1143 repository_id = Column('repository_id', String(250), primary_key=True)
1145 repository_path = Column('repository_path', Text)
1144 repository_path = Column('repository_path', Text)
1146 version = Column('version', Integer)
1145 version = Column('version', Integer)
@@ -1,1148 +1,1147 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2019 RhodeCode GmbH
3 # Copyright (C) 2010-2019 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import os
21 import os
22 import time
22 import time
23 import logging
23 import logging
24 import datetime
24 import datetime
25 import traceback
25 import traceback
26 import hashlib
26 import hashlib
27 import collections
27 import collections
28
28
29 from sqlalchemy import *
29 from sqlalchemy import *
30 from sqlalchemy.ext.hybrid import hybrid_property
30 from sqlalchemy.ext.hybrid import hybrid_property
31 from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
31 from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
32 from sqlalchemy.exc import DatabaseError
32 from sqlalchemy.exc import DatabaseError
33 from beaker.cache import cache_region, region_invalidate
33 from beaker.cache import cache_region, region_invalidate
34 from webob.exc import HTTPNotFound
34 from webob.exc import HTTPNotFound
35
35
36 from rhodecode.translation import _
36 from rhodecode.translation import _
37
37
38 from rhodecode.lib.vcs import get_backend
38 from rhodecode.lib.vcs import get_backend
39 from rhodecode.lib.vcs.utils.helpers import get_scm
39 from rhodecode.lib.vcs.utils.helpers import get_scm
40 from rhodecode.lib.vcs.exceptions import VCSError
40 from rhodecode.lib.vcs.exceptions import VCSError
41 from zope.cachedescriptors.property import Lazy as LazyProperty
41 from zope.cachedescriptors.property import Lazy as LazyProperty
42 from rhodecode.lib.vcs.backends.base import EmptyCommit
42 from rhodecode.lib.vcs.backends.base import EmptyCommit
43
43
44 from rhodecode.lib.utils2 import str2bool, safe_str, get_commit_safe, \
44 from rhodecode.lib.utils2 import str2bool, safe_str, get_commit_safe, \
45 safe_unicode, remove_suffix, remove_prefix, time_to_datetime
45 safe_unicode, remove_suffix, remove_prefix, time_to_datetime
46 from rhodecode.lib.ext_json import json
46 from rhodecode.lib.ext_json import json
47 from rhodecode.lib.caching_query import FromCache
47 from rhodecode.lib.caching_query import FromCache
48
48
49 from rhodecode.model.meta import Base, Session
49 from rhodecode.model.meta import Base, Session
50
50
51 URL_SEP = '/'
51 URL_SEP = '/'
52 log = logging.getLogger(__name__)
52 log = logging.getLogger(__name__)
53
53
54 #==============================================================================
54 #==============================================================================
55 # BASE CLASSES
55 # BASE CLASSES
56 #==============================================================================
56 #==============================================================================
57
57
58 _hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest()
58 _hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest()
59
59
60
60
61 class BaseModel(object):
61 class BaseModel(object):
62 """
62 """
63 Base Model for all classes
63 Base Model for all classes
64 """
64 """
65
65
66 @classmethod
66 @classmethod
67 def _get_keys(cls):
67 def _get_keys(cls):
68 """return column names for this model """
68 """return column names for this model """
69 return class_mapper(cls).c.keys()
69 return class_mapper(cls).c.keys()
70
70
71 def get_dict(self):
71 def get_dict(self):
72 """
72 """
73 return dict with keys and values corresponding
73 return dict with keys and values corresponding
74 to this model data """
74 to this model data """
75
75
76 d = {}
76 d = {}
77 for k in self._get_keys():
77 for k in self._get_keys():
78 d[k] = getattr(self, k)
78 d[k] = getattr(self, k)
79
79
80 # also use __json__() if present to get additional fields
80 # also use __json__() if present to get additional fields
81 _json_attr = getattr(self, '__json__', None)
81 _json_attr = getattr(self, '__json__', None)
82 if _json_attr:
82 if _json_attr:
83 # update with attributes from __json__
83 # update with attributes from __json__
84 if callable(_json_attr):
84 if callable(_json_attr):
85 _json_attr = _json_attr()
85 _json_attr = _json_attr()
86 for k, val in _json_attr.iteritems():
86 for k, val in _json_attr.iteritems():
87 d[k] = val
87 d[k] = val
88 return d
88 return d
89
89
90 def get_appstruct(self):
90 def get_appstruct(self):
91 """return list with keys and values tupples corresponding
91 """return list with keys and values tupples corresponding
92 to this model data """
92 to this model data """
93
93
94 l = []
94 l = []
95 for k in self._get_keys():
95 for k in self._get_keys():
96 l.append((k, getattr(self, k),))
96 l.append((k, getattr(self, k),))
97 return l
97 return l
98
98
99 def populate_obj(self, populate_dict):
99 def populate_obj(self, populate_dict):
100 """populate model with data from given populate_dict"""
100 """populate model with data from given populate_dict"""
101
101
102 for k in self._get_keys():
102 for k in self._get_keys():
103 if k in populate_dict:
103 if k in populate_dict:
104 setattr(self, k, populate_dict[k])
104 setattr(self, k, populate_dict[k])
105
105
106 @classmethod
106 @classmethod
107 def query(cls):
107 def query(cls):
108 return Session().query(cls)
108 return Session().query(cls)
109
109
110 @classmethod
110 @classmethod
111 def get(cls, id_):
111 def get(cls, id_):
112 if id_:
112 if id_:
113 return cls.query().get(id_)
113 return cls.query().get(id_)
114
114
115 @classmethod
115 @classmethod
116 def get_or_404(cls, id_):
116 def get_or_404(cls, id_):
117 try:
117 try:
118 id_ = int(id_)
118 id_ = int(id_)
119 except (TypeError, ValueError):
119 except (TypeError, ValueError):
120 raise HTTPNotFound
120 raise HTTPNotFound
121
121
122 res = cls.query().get(id_)
122 res = cls.query().get(id_)
123 if not res:
123 if not res:
124 raise HTTPNotFound
124 raise HTTPNotFound
125 return res
125 return res
126
126
127 @classmethod
127 @classmethod
128 def getAll(cls):
128 def getAll(cls):
129 # deprecated and left for backward compatibility
129 # deprecated and left for backward compatibility
130 return cls.get_all()
130 return cls.get_all()
131
131
132 @classmethod
132 @classmethod
133 def get_all(cls):
133 def get_all(cls):
134 return cls.query().all()
134 return cls.query().all()
135
135
136 @classmethod
136 @classmethod
137 def delete(cls, id_):
137 def delete(cls, id_):
138 obj = cls.query().get(id_)
138 obj = cls.query().get(id_)
139 Session().delete(obj)
139 Session().delete(obj)
140
140
141 def __repr__(self):
141 def __repr__(self):
142 if hasattr(self, '__unicode__'):
142 if hasattr(self, '__unicode__'):
143 # python repr needs to return str
143 # python repr needs to return str
144 return safe_str(self.__unicode__())
144 return safe_str(self.__unicode__())
145 return '<DB:%s>' % (self.__class__.__name__)
145 return '<DB:%s>' % (self.__class__.__name__)
146
146
147
147
148 class RhodeCodeSetting(Base, BaseModel):
148 class RhodeCodeSetting(Base, BaseModel):
149 __tablename__ = 'rhodecode_settings'
149 __tablename__ = 'rhodecode_settings'
150 __table_args__ = (
150 __table_args__ = (
151 UniqueConstraint('app_settings_name'),
151 UniqueConstraint('app_settings_name'),
152 {'extend_existing': True, 'mysql_engine': 'InnoDB',
152 {'extend_existing': True, 'mysql_engine': 'InnoDB',
153 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
153 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
154 )
154 )
155 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
155 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
156 app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None)
156 app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None)
157 _app_settings_value = Column("app_settings_value", String(255), nullable=True, unique=None, default=None)
157 _app_settings_value = Column("app_settings_value", String(255), nullable=True, unique=None, default=None)
158 _app_settings_type = Column("app_settings_type", String(255), nullable=True, unique=None, default=None)
158 _app_settings_type = Column("app_settings_type", String(255), nullable=True, unique=None, default=None)
159
159
160 def __init__(self, key='', val='', type='unicode'):
160 def __init__(self, key='', val='', type='unicode'):
161 self.app_settings_name = key
161 self.app_settings_name = key
162 self.app_settings_value = val
162 self.app_settings_value = val
163 self.app_settings_type = type
163 self.app_settings_type = type
164
164
165 @validates('_app_settings_value')
165 @validates('_app_settings_value')
166 def validate_settings_value(self, key, val):
166 def validate_settings_value(self, key, val):
167 assert type(val) == unicode
167 assert type(val) == unicode
168 return val
168 return val
169
169
170 @hybrid_property
170 @hybrid_property
171 def app_settings_value(self):
171 def app_settings_value(self):
172 v = self._app_settings_value
172 v = self._app_settings_value
173 if self.app_settings_name in ["ldap_active",
173 if self.app_settings_name in ["ldap_active",
174 "default_repo_enable_statistics",
174 "default_repo_enable_statistics",
175 "default_repo_enable_locking",
175 "default_repo_enable_locking",
176 "default_repo_private",
176 "default_repo_private",
177 "default_repo_enable_downloads"]:
177 "default_repo_enable_downloads"]:
178 v = str2bool(v)
178 v = str2bool(v)
179 return v
179 return v
180
180
181 @app_settings_value.setter
181 @app_settings_value.setter
182 def app_settings_value(self, val):
182 def app_settings_value(self, val):
183 """
183 """
184 Setter that will always make sure we use unicode in app_settings_value
184 Setter that will always make sure we use unicode in app_settings_value
185
185
186 :param val:
186 :param val:
187 """
187 """
188 self._app_settings_value = safe_unicode(val)
188 self._app_settings_value = safe_unicode(val)
189
189
190 def __unicode__(self):
190 def __unicode__(self):
191 return u"<%s('%s:%s')>" % (
191 return u"<%s('%s:%s')>" % (
192 self.__class__.__name__,
192 self.__class__.__name__,
193 self.app_settings_name, self.app_settings_value
193 self.app_settings_name, self.app_settings_value
194 )
194 )
195
195
196
196
197 class RhodeCodeUi(Base, BaseModel):
197 class RhodeCodeUi(Base, BaseModel):
198 __tablename__ = 'rhodecode_ui'
198 __tablename__ = 'rhodecode_ui'
199 __table_args__ = (
199 __table_args__ = (
200 UniqueConstraint('ui_key'),
200 UniqueConstraint('ui_key'),
201 {'extend_existing': True, 'mysql_engine': 'InnoDB',
201 {'extend_existing': True, 'mysql_engine': 'InnoDB',
202 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
202 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
203 )
203 )
204
204
205 HOOK_REPO_SIZE = 'changegroup.repo_size'
205 HOOK_REPO_SIZE = 'changegroup.repo_size'
206 HOOK_PUSH = 'changegroup.push_logger'
206 HOOK_PUSH = 'changegroup.push_logger'
207 HOOK_PRE_PUSH = 'prechangegroup.pre_push'
207 HOOK_PRE_PUSH = 'prechangegroup.pre_push'
208 HOOK_PULL = 'outgoing.pull_logger'
208 HOOK_PULL = 'outgoing.pull_logger'
209 HOOK_PRE_PULL = 'preoutgoing.pre_pull'
209 HOOK_PRE_PULL = 'preoutgoing.pre_pull'
210
210
211 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
211 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
212 ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None)
212 ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None)
213 ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None)
213 ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None)
214 ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None)
214 ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None)
215 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
215 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
216
216
217
217
218
218
219 class User(Base, BaseModel):
219 class User(Base, BaseModel):
220 __tablename__ = 'users'
220 __tablename__ = 'users'
221 __table_args__ = (
221 __table_args__ = (
222 UniqueConstraint('username'), UniqueConstraint('email'),
222 UniqueConstraint('username'), UniqueConstraint('email'),
223 Index('u_username_idx', 'username'),
223 Index('u_username_idx', 'username'),
224 Index('u_email_idx', 'email'),
224 Index('u_email_idx', 'email'),
225 {'extend_existing': True, 'mysql_engine': 'InnoDB',
225 {'extend_existing': True, 'mysql_engine': 'InnoDB',
226 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
226 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
227 )
227 )
228 DEFAULT_USER = 'default'
228 DEFAULT_USER = 'default'
229
229
230 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
230 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
231 username = Column("username", String(255), nullable=True, unique=None, default=None)
231 username = Column("username", String(255), nullable=True, unique=None, default=None)
232 password = Column("password", String(255), nullable=True, unique=None, default=None)
232 password = Column("password", String(255), nullable=True, unique=None, default=None)
233 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
233 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
234 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
234 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
235 name = Column("firstname", String(255), nullable=True, unique=None, default=None)
235 name = Column("firstname", String(255), nullable=True, unique=None, default=None)
236 lastname = Column("lastname", String(255), nullable=True, unique=None, default=None)
236 lastname = Column("lastname", String(255), nullable=True, unique=None, default=None)
237 _email = Column("email", String(255), nullable=True, unique=None, default=None)
237 _email = Column("email", String(255), nullable=True, unique=None, default=None)
238 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
238 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
239 ldap_dn = Column("ldap_dn", String(255), nullable=True, unique=None, default=None)
239 ldap_dn = Column("ldap_dn", String(255), nullable=True, unique=None, default=None)
240 api_key = Column("api_key", String(255), nullable=True, unique=None, default=None)
240 api_key = Column("api_key", String(255), nullable=True, unique=None, default=None)
241 inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
241 inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
242
242
243 user_log = relationship('UserLog')
243 user_log = relationship('UserLog')
244 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
244 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
245
245
246 repositories = relationship('Repository')
246 repositories = relationship('Repository')
247 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
247 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
248 followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all')
248 followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all')
249
249
250 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
250 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
251 repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all')
251 repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all')
252
252
253 group_member = relationship('UserGroupMember', cascade='all')
253 group_member = relationship('UserGroupMember', cascade='all')
254
254
255 notifications = relationship('UserNotification', cascade='all')
255 notifications = relationship('UserNotification', cascade='all')
256 # notifications assigned to this user
256 # notifications assigned to this user
257 user_created_notifications = relationship('Notification', cascade='all')
257 user_created_notifications = relationship('Notification', cascade='all')
258 # comments created by this user
258 # comments created by this user
259 user_comments = relationship('ChangesetComment', cascade='all')
259 user_comments = relationship('ChangesetComment', cascade='all')
260 user_emails = relationship('UserEmailMap', cascade='all')
260 user_emails = relationship('UserEmailMap', cascade='all')
261
261
262 @hybrid_property
262 @hybrid_property
263 def email(self):
263 def email(self):
264 return self._email
264 return self._email
265
265
266 @email.setter
266 @email.setter
267 def email(self, val):
267 def email(self, val):
268 self._email = val.lower() if val else None
268 self._email = val.lower() if val else None
269
269
270 @property
270 @property
271 def firstname(self):
271 def firstname(self):
272 # alias for future
272 # alias for future
273 return self.name
273 return self.name
274
274
275 @property
275 @property
276 def username_and_name(self):
276 def username_and_name(self):
277 return '%s (%s %s)' % (self.username, self.firstname, self.lastname)
277 return '%s (%s %s)' % (self.username, self.firstname, self.lastname)
278
278
279 @property
279 @property
280 def full_name(self):
280 def full_name(self):
281 return '%s %s' % (self.firstname, self.lastname)
281 return '%s %s' % (self.firstname, self.lastname)
282
282
283 @property
283 @property
284 def full_contact(self):
284 def full_contact(self):
285 return '%s %s <%s>' % (self.firstname, self.lastname, self.email)
285 return '%s %s <%s>' % (self.firstname, self.lastname, self.email)
286
286
287 @property
287 @property
288 def short_contact(self):
288 def short_contact(self):
289 return '%s %s' % (self.firstname, self.lastname)
289 return '%s %s' % (self.firstname, self.lastname)
290
290
291 @property
291 @property
292 def is_admin(self):
292 def is_admin(self):
293 return self.admin
293 return self.admin
294
294
295 @classmethod
295 @classmethod
296 def get_by_username(cls, username, case_insensitive=False, cache=False):
296 def get_by_username(cls, username, case_insensitive=False, cache=False):
297 if case_insensitive:
297 if case_insensitive:
298 q = cls.query().filter(cls.username.ilike(username))
298 q = cls.query().filter(cls.username.ilike(username))
299 else:
299 else:
300 q = cls.query().filter(cls.username == username)
300 q = cls.query().filter(cls.username == username)
301
301
302 if cache:
302 if cache:
303 q = q.options(FromCache(
303 q = q.options(FromCache(
304 "sql_cache_short",
304 "sql_cache_short",
305 "get_user_%s" % _hash_key(username)
305 "get_user_%s" % _hash_key(username)
306 )
306 )
307 )
307 )
308 return q.scalar()
308 return q.scalar()
309
309
310 @classmethod
310 @classmethod
311 def get_by_auth_token(cls, auth_token, cache=False):
311 def get_by_auth_token(cls, auth_token, cache=False):
312 q = cls.query().filter(cls.api_key == auth_token)
312 q = cls.query().filter(cls.api_key == auth_token)
313
313
314 if cache:
314 if cache:
315 q = q.options(FromCache("sql_cache_short",
315 q = q.options(FromCache("sql_cache_short",
316 "get_auth_token_%s" % auth_token))
316 "get_auth_token_%s" % auth_token))
317 return q.scalar()
317 return q.scalar()
318
318
319 @classmethod
319 @classmethod
320 def get_by_email(cls, email, case_insensitive=False, cache=False):
320 def get_by_email(cls, email, case_insensitive=False, cache=False):
321 if case_insensitive:
321 if case_insensitive:
322 q = cls.query().filter(cls.email.ilike(email))
322 q = cls.query().filter(cls.email.ilike(email))
323 else:
323 else:
324 q = cls.query().filter(cls.email == email)
324 q = cls.query().filter(cls.email == email)
325
325
326 if cache:
326 if cache:
327 q = q.options(FromCache("sql_cache_short",
327 q = q.options(FromCache("sql_cache_short",
328 "get_email_key_%s" % email))
328 "get_email_key_%s" % email))
329
329
330 ret = q.scalar()
330 ret = q.scalar()
331 if ret is None:
331 if ret is None:
332 q = UserEmailMap.query()
332 q = UserEmailMap.query()
333 # try fetching in alternate email map
333 # try fetching in alternate email map
334 if case_insensitive:
334 if case_insensitive:
335 q = q.filter(UserEmailMap.email.ilike(email))
335 q = q.filter(UserEmailMap.email.ilike(email))
336 else:
336 else:
337 q = q.filter(UserEmailMap.email == email)
337 q = q.filter(UserEmailMap.email == email)
338 q = q.options(joinedload(UserEmailMap.user))
338 q = q.options(joinedload(UserEmailMap.user))
339 if cache:
339 if cache:
340 q = q.options(FromCache("sql_cache_short",
340 q = q.options(FromCache("sql_cache_short",
341 "get_email_map_key_%s" % email))
341 "get_email_map_key_%s" % email))
342 ret = getattr(q.scalar(), 'user', None)
342 ret = getattr(q.scalar(), 'user', None)
343
343
344 return ret
344 return ret
345
345
346 @classmethod
346 @classmethod
347 def get_first_admin(cls):
347 def get_first_admin(cls):
348 user = User.query().filter(User.admin == True).first()
348 user = User.query().filter(User.admin == True).first()
349 if user is None:
349 if user is None:
350 raise Exception('Missing administrative account!')
350 raise Exception('Missing administrative account!')
351 return user
351 return user
352
352
353 @classmethod
353 @classmethod
354 def get_default_user(cls, cache=False):
354 def get_default_user(cls, cache=False):
355 user = User.get_by_username(User.DEFAULT_USER, cache=cache)
355 user = User.get_by_username(User.DEFAULT_USER, cache=cache)
356 if user is None:
356 if user is None:
357 raise Exception('Missing default account!')
357 raise Exception('Missing default account!')
358 return user
358 return user
359
359
360
360
361
361
362
362
363 class UserEmailMap(Base, BaseModel):
363 class UserEmailMap(Base, BaseModel):
364 __tablename__ = 'user_email_map'
364 __tablename__ = 'user_email_map'
365 __table_args__ = (
365 __table_args__ = (
366 Index('uem_email_idx', 'email'),
366 Index('uem_email_idx', 'email'),
367 UniqueConstraint('email'),
367 UniqueConstraint('email'),
368 {'extend_existing': True, 'mysql_engine': 'InnoDB',
368 {'extend_existing': True, 'mysql_engine': 'InnoDB',
369 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
369 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
370 )
370 )
371 __mapper_args__ = {}
371 __mapper_args__ = {}
372
372
373 email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
373 email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
374 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
374 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
375 _email = Column("email", String(255), nullable=True, unique=False, default=None)
375 _email = Column("email", String(255), nullable=True, unique=False, default=None)
376 user = relationship('User', lazy='joined')
376 user = relationship('User', lazy='joined')
377
377
378 @validates('_email')
378 @validates('_email')
379 def validate_email(self, key, email):
379 def validate_email(self, key, email):
380 # check if this email is not main one
380 # check if this email is not main one
381 main_email = Session().query(User).filter(User.email == email).scalar()
381 main_email = Session().query(User).filter(User.email == email).scalar()
382 if main_email is not None:
382 if main_email is not None:
383 raise AttributeError('email %s is present is user table' % email)
383 raise AttributeError('email %s is present is user table' % email)
384 return email
384 return email
385
385
386 @hybrid_property
386 @hybrid_property
387 def email(self):
387 def email(self):
388 return self._email
388 return self._email
389
389
390 @email.setter
390 @email.setter
391 def email(self, val):
391 def email(self, val):
392 self._email = val.lower() if val else None
392 self._email = val.lower() if val else None
393
393
394
394
395 class UserIpMap(Base, BaseModel):
395 class UserIpMap(Base, BaseModel):
396 __tablename__ = 'user_ip_map'
396 __tablename__ = 'user_ip_map'
397 __table_args__ = (
397 __table_args__ = (
398 UniqueConstraint('user_id', 'ip_addr'),
398 UniqueConstraint('user_id', 'ip_addr'),
399 {'extend_existing': True, 'mysql_engine': 'InnoDB',
399 {'extend_existing': True, 'mysql_engine': 'InnoDB',
400 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
400 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
401 )
401 )
402 __mapper_args__ = {}
402 __mapper_args__ = {}
403
403
404 ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
404 ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
405 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
405 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
406 ip_addr = Column("ip_addr", String(255), nullable=True, unique=False, default=None)
406 ip_addr = Column("ip_addr", String(255), nullable=True, unique=False, default=None)
407 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
407 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
408 user = relationship('User', lazy='joined')
408 user = relationship('User', lazy='joined')
409
409
410
410
411 class UserLog(Base, BaseModel):
411 class UserLog(Base, BaseModel):
412 __tablename__ = 'user_logs'
412 __tablename__ = 'user_logs'
413 __table_args__ = (
413 __table_args__ = (
414 {'extend_existing': True, 'mysql_engine': 'InnoDB',
414 {'extend_existing': True, 'mysql_engine': 'InnoDB',
415 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
415 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
416 )
416 )
417 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
417 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
418 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
418 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
419 username = Column("username", String(255), nullable=True, unique=None, default=None)
419 username = Column("username", String(255), nullable=True, unique=None, default=None)
420 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
420 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
421 repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None)
421 repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None)
422 user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None)
422 user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None)
423 action = Column("action", String(1200000), nullable=True, unique=None, default=None)
423 action = Column("action", String(1200000), nullable=True, unique=None, default=None)
424 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
424 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
425
425
426 def __unicode__(self):
426 def __unicode__(self):
427 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
427 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
428 self.repository_name,
428 self.repository_name,
429 self.action)
429 self.action)
430
430
431 user = relationship('User')
431 user = relationship('User')
432 repository = relationship('Repository', cascade='')
432 repository = relationship('Repository', cascade='')
433
433
434
434
435 class UserGroup(Base, BaseModel):
435 class UserGroup(Base, BaseModel):
436 __tablename__ = 'users_groups'
436 __tablename__ = 'users_groups'
437 __table_args__ = (
437 __table_args__ = (
438 {'extend_existing': True, 'mysql_engine': 'InnoDB',
438 {'extend_existing': True, 'mysql_engine': 'InnoDB',
439 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
439 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
440 )
440 )
441
441
442 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
442 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
443 users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None)
443 users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None)
444 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
444 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
445 inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
445 inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
446 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
446 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
447
447
448 members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
448 members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
449 users_group_to_perm = relationship('UserGroupToPerm', cascade='all')
449 users_group_to_perm = relationship('UserGroupToPerm', cascade='all')
450 users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
450 users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
451 users_group_repo_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
451 users_group_repo_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
452 user_user_group_to_perm = relationship('UserUserGroupToPerm', cascade='all')
452 user_user_group_to_perm = relationship('UserUserGroupToPerm', cascade='all')
453 user_group_user_group_to_perm = relationship('UserGroupUserGroupToPerm ', primaryjoin="UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id", cascade='all')
453 user_group_user_group_to_perm = relationship('UserGroupUserGroupToPerm ', primaryjoin="UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id", cascade='all')
454
454
455 user = relationship('User')
455 user = relationship('User')
456
456
457 def __unicode__(self):
457 def __unicode__(self):
458 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
458 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
459 self.users_group_id,
459 self.users_group_id,
460 self.users_group_name)
460 self.users_group_name)
461
461
462 @classmethod
462 @classmethod
463 def get_by_group_name(cls, group_name, cache=False,
463 def get_by_group_name(cls, group_name, cache=False,
464 case_insensitive=False):
464 case_insensitive=False):
465 if case_insensitive:
465 if case_insensitive:
466 q = cls.query().filter(cls.users_group_name.ilike(group_name))
466 q = cls.query().filter(cls.users_group_name.ilike(group_name))
467 else:
467 else:
468 q = cls.query().filter(cls.users_group_name == group_name)
468 q = cls.query().filter(cls.users_group_name == group_name)
469 if cache:
469 if cache:
470 q = q.options(FromCache(
470 q = q.options(FromCache(
471 "sql_cache_short",
471 "sql_cache_short",
472 "get_user_%s" % _hash_key(group_name)
472 "get_user_%s" % _hash_key(group_name)
473 )
473 )
474 )
474 )
475 return q.scalar()
475 return q.scalar()
476
476
477 @classmethod
477 @classmethod
478 def get(cls, user_group_id, cache=False):
478 def get(cls, user_group_id, cache=False):
479 user_group = cls.query()
479 user_group = cls.query()
480 if cache:
480 if cache:
481 user_group = user_group.options(FromCache("sql_cache_short",
481 user_group = user_group.options(FromCache("sql_cache_short",
482 "get_users_group_%s" % user_group_id))
482 "get_users_group_%s" % user_group_id))
483 return user_group.get(user_group_id)
483 return user_group.get(user_group_id)
484
484
485
485
486 class UserGroupMember(Base, BaseModel):
486 class UserGroupMember(Base, BaseModel):
487 __tablename__ = 'users_groups_members'
487 __tablename__ = 'users_groups_members'
488 __table_args__ = (
488 __table_args__ = (
489 {'extend_existing': True, 'mysql_engine': 'InnoDB',
489 {'extend_existing': True, 'mysql_engine': 'InnoDB',
490 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
490 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
491 )
491 )
492
492
493 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
493 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
494 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
494 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
495 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
495 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
496
496
497 user = relationship('User', lazy='joined')
497 user = relationship('User', lazy='joined')
498 users_group = relationship('UserGroup')
498 users_group = relationship('UserGroup')
499
499
500 def __init__(self, gr_id='', u_id=''):
500 def __init__(self, gr_id='', u_id=''):
501 self.users_group_id = gr_id
501 self.users_group_id = gr_id
502 self.user_id = u_id
502 self.user_id = u_id
503
503
504
504
505 class RepositoryField(Base, BaseModel):
505 class RepositoryField(Base, BaseModel):
506 __tablename__ = 'repositories_fields'
506 __tablename__ = 'repositories_fields'
507 __table_args__ = (
507 __table_args__ = (
508 UniqueConstraint('repository_id', 'field_key'), # no-multi field
508 UniqueConstraint('repository_id', 'field_key'), # no-multi field
509 {'extend_existing': True, 'mysql_engine': 'InnoDB',
509 {'extend_existing': True, 'mysql_engine': 'InnoDB',
510 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
510 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
511 )
511 )
512 PREFIX = 'ex_' # prefix used in form to not conflict with already existing fields
512 PREFIX = 'ex_' # prefix used in form to not conflict with already existing fields
513
513
514 repo_field_id = Column("repo_field_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
514 repo_field_id = Column("repo_field_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
515 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
515 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
516 field_key = Column("field_key", String(250))
516 field_key = Column("field_key", String(250))
517 field_label = Column("field_label", String(1024), nullable=False)
517 field_label = Column("field_label", String(1024), nullable=False)
518 field_value = Column("field_value", String(10000), nullable=False)
518 field_value = Column("field_value", String(10000), nullable=False)
519 field_desc = Column("field_desc", String(1024), nullable=False)
519 field_desc = Column("field_desc", String(1024), nullable=False)
520 field_type = Column("field_type", String(256), nullable=False, unique=None)
520 field_type = Column("field_type", String(256), nullable=False, unique=None)
521 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
521 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
522
522
523 repository = relationship('Repository')
523 repository = relationship('Repository')
524
524
525 @classmethod
525 @classmethod
526 def get_by_key_name(cls, key, repo):
526 def get_by_key_name(cls, key, repo):
527 row = cls.query()\
527 row = cls.query()\
528 .filter(cls.repository == repo)\
528 .filter(cls.repository == repo)\
529 .filter(cls.field_key == key).scalar()
529 .filter(cls.field_key == key).scalar()
530 return row
530 return row
531
531
532
532
533 class Repository(Base, BaseModel):
533 class Repository(Base, BaseModel):
534 __tablename__ = 'repositories'
534 __tablename__ = 'repositories'
535 __table_args__ = (
535 __table_args__ = (
536 UniqueConstraint('repo_name'),
536 UniqueConstraint('repo_name'),
537 Index('r_repo_name_idx', 'repo_name'),
537 Index('r_repo_name_idx', 'repo_name'),
538 {'extend_existing': True, 'mysql_engine': 'InnoDB',
538 {'extend_existing': True, 'mysql_engine': 'InnoDB',
539 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
539 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
540 )
540 )
541
541
542 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
542 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
543 repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None)
543 repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None)
544 clone_uri = Column("clone_uri", String(255), nullable=True, unique=False, default=None)
544 clone_uri = Column("clone_uri", String(255), nullable=True, unique=False, default=None)
545 repo_type = Column("repo_type", String(255), nullable=False, unique=False, default=None)
545 repo_type = Column("repo_type", String(255), nullable=False, unique=False, default=None)
546 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
546 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
547 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
547 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
548 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
548 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
549 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
549 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
550 description = Column("description", String(10000), nullable=True, unique=None, default=None)
550 description = Column("description", String(10000), nullable=True, unique=None, default=None)
551 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
551 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
552 updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
552 updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
553 landing_rev = Column("landing_revision", String(255), nullable=False, unique=False, default=None)
553 landing_rev = Column("landing_revision", String(255), nullable=False, unique=False, default=None)
554 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
554 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
555 _locked = Column("locked", String(255), nullable=True, unique=False, default=None)
555 _locked = Column("locked", String(255), nullable=True, unique=False, default=None)
556 _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) #JSON data
556 _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) #JSON data
557
557
558 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
558 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
559 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
559 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
560
560
561 user = relationship('User')
561 user = relationship('User')
562 fork = relationship('Repository', remote_side=repo_id)
562 fork = relationship('Repository', remote_side=repo_id)
563 group = relationship('RepoGroup')
563 group = relationship('RepoGroup')
564 repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
564 repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
565 users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
565 users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
566 stats = relationship('Statistics', cascade='all', uselist=False)
566 stats = relationship('Statistics', cascade='all', uselist=False)
567
567
568 followers = relationship('UserFollowing',
568 followers = relationship('UserFollowing',
569 primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id',
569 primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id',
570 cascade='all')
570 cascade='all')
571 extra_fields = relationship('RepositoryField',
571 extra_fields = relationship('RepositoryField',
572 cascade="all, delete, delete-orphan")
572 cascade="all, delete, delete-orphan")
573
573
574 logs = relationship('UserLog')
574 logs = relationship('UserLog')
575 comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan")
575 comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan")
576
576
577 pull_requests_org = relationship('PullRequest',
577 pull_requests_org = relationship('PullRequest',
578 primaryjoin='PullRequest.org_repo_id==Repository.repo_id',
578 primaryjoin='PullRequest.org_repo_id==Repository.repo_id',
579 cascade="all, delete, delete-orphan")
579 cascade="all, delete, delete-orphan")
580
580
581 pull_requests_other = relationship('PullRequest',
581 pull_requests_other = relationship('PullRequest',
582 primaryjoin='PullRequest.other_repo_id==Repository.repo_id',
582 primaryjoin='PullRequest.other_repo_id==Repository.repo_id',
583 cascade="all, delete, delete-orphan")
583 cascade="all, delete, delete-orphan")
584
584
585 def __unicode__(self):
585 def __unicode__(self):
586 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id,
586 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id,
587 safe_unicode(self.repo_name))
587 safe_unicode(self.repo_name))
588
588
589 @classmethod
589 @classmethod
590 def get_by_repo_name(cls, repo_name):
590 def get_by_repo_name(cls, repo_name):
591 q = Session().query(cls).filter(cls.repo_name == repo_name)
591 q = Session().query(cls).filter(cls.repo_name == repo_name)
592 q = q.options(joinedload(Repository.fork))\
592 q = q.options(joinedload(Repository.fork))\
593 .options(joinedload(Repository.user))\
593 .options(joinedload(Repository.user))\
594 .options(joinedload(Repository.group))
594 .options(joinedload(Repository.group))
595 return q.scalar()
595 return q.scalar()
596
596
597
597
598 class RepoGroup(Base, BaseModel):
598 class RepoGroup(Base, BaseModel):
599 __tablename__ = 'groups'
599 __tablename__ = 'groups'
600 __table_args__ = (
600 __table_args__ = (
601 UniqueConstraint('group_name', 'group_parent_id'),
601 UniqueConstraint('group_name', 'group_parent_id'),
602 CheckConstraint('group_id != group_parent_id'),
603 {'extend_existing': True, 'mysql_engine': 'InnoDB',
602 {'extend_existing': True, 'mysql_engine': 'InnoDB',
604 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
603 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
605 )
604 )
606 __mapper_args__ = {'order_by': 'group_name'}
605 __mapper_args__ = {'order_by': 'group_name'}
607
606
608 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
607 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
609 group_name = Column("group_name", String(255), nullable=False, unique=True, default=None)
608 group_name = Column("group_name", String(255), nullable=False, unique=True, default=None)
610 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
609 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
611 group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None)
610 group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None)
612 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
611 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
613 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
612 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
614
613
615 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
614 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
616 users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
615 users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
617 parent_group = relationship('RepoGroup', remote_side=group_id)
616 parent_group = relationship('RepoGroup', remote_side=group_id)
618 user = relationship('User')
617 user = relationship('User')
619
618
620 def __init__(self, group_name='', parent_group=None):
619 def __init__(self, group_name='', parent_group=None):
621 self.group_name = group_name
620 self.group_name = group_name
622 self.parent_group = parent_group
621 self.parent_group = parent_group
623
622
624 def __unicode__(self):
623 def __unicode__(self):
625 return u"<%s('id:%s:%s')>" % (self.__class__.__name__, self.group_id,
624 return u"<%s('id:%s:%s')>" % (self.__class__.__name__, self.group_id,
626 self.group_name)
625 self.group_name)
627
626
628 @classmethod
627 @classmethod
629 def url_sep(cls):
628 def url_sep(cls):
630 return URL_SEP
629 return URL_SEP
631
630
632 @classmethod
631 @classmethod
633 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
632 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
634 if case_insensitive:
633 if case_insensitive:
635 gr = cls.query()\
634 gr = cls.query()\
636 .filter(cls.group_name.ilike(group_name))
635 .filter(cls.group_name.ilike(group_name))
637 else:
636 else:
638 gr = cls.query()\
637 gr = cls.query()\
639 .filter(cls.group_name == group_name)
638 .filter(cls.group_name == group_name)
640 if cache:
639 if cache:
641 gr = gr.options(FromCache(
640 gr = gr.options(FromCache(
642 "sql_cache_short",
641 "sql_cache_short",
643 "get_group_%s" % _hash_key(group_name)
642 "get_group_%s" % _hash_key(group_name)
644 )
643 )
645 )
644 )
646 return gr.scalar()
645 return gr.scalar()
647
646
648
647
649 class Permission(Base, BaseModel):
648 class Permission(Base, BaseModel):
650 __tablename__ = 'permissions'
649 __tablename__ = 'permissions'
651 __table_args__ = (
650 __table_args__ = (
652 Index('p_perm_name_idx', 'permission_name'),
651 Index('p_perm_name_idx', 'permission_name'),
653 {'extend_existing': True, 'mysql_engine': 'InnoDB',
652 {'extend_existing': True, 'mysql_engine': 'InnoDB',
654 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
653 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
655 )
654 )
656 PERMS = [
655 PERMS = [
657 ('hg.admin', _('RhodeCode Administrator')),
656 ('hg.admin', _('RhodeCode Administrator')),
658
657
659 ('repository.none', _('Repository no access')),
658 ('repository.none', _('Repository no access')),
660 ('repository.read', _('Repository read access')),
659 ('repository.read', _('Repository read access')),
661 ('repository.write', _('Repository write access')),
660 ('repository.write', _('Repository write access')),
662 ('repository.admin', _('Repository admin access')),
661 ('repository.admin', _('Repository admin access')),
663
662
664 ('group.none', _('Repository group no access')),
663 ('group.none', _('Repository group no access')),
665 ('group.read', _('Repository group read access')),
664 ('group.read', _('Repository group read access')),
666 ('group.write', _('Repository group write access')),
665 ('group.write', _('Repository group write access')),
667 ('group.admin', _('Repository group admin access')),
666 ('group.admin', _('Repository group admin access')),
668
667
669 ('usergroup.none', _('User group no access')),
668 ('usergroup.none', _('User group no access')),
670 ('usergroup.read', _('User group read access')),
669 ('usergroup.read', _('User group read access')),
671 ('usergroup.write', _('User group write access')),
670 ('usergroup.write', _('User group write access')),
672 ('usergroup.admin', _('User group admin access')),
671 ('usergroup.admin', _('User group admin access')),
673
672
674 ('hg.repogroup.create.false', _('Repository Group creation disabled')),
673 ('hg.repogroup.create.false', _('Repository Group creation disabled')),
675 ('hg.repogroup.create.true', _('Repository Group creation enabled')),
674 ('hg.repogroup.create.true', _('Repository Group creation enabled')),
676
675
677 ('hg.usergroup.create.false', _('User Group creation disabled')),
676 ('hg.usergroup.create.false', _('User Group creation disabled')),
678 ('hg.usergroup.create.true', _('User Group creation enabled')),
677 ('hg.usergroup.create.true', _('User Group creation enabled')),
679
678
680 ('hg.create.none', _('Repository creation disabled')),
679 ('hg.create.none', _('Repository creation disabled')),
681 ('hg.create.repository', _('Repository creation enabled')),
680 ('hg.create.repository', _('Repository creation enabled')),
682
681
683 ('hg.fork.none', _('Repository forking disabled')),
682 ('hg.fork.none', _('Repository forking disabled')),
684 ('hg.fork.repository', _('Repository forking enabled')),
683 ('hg.fork.repository', _('Repository forking enabled')),
685
684
686 ('hg.register.none', _('Registration disabled')),
685 ('hg.register.none', _('Registration disabled')),
687 ('hg.register.manual_activate', _('User Registration with manual account activation')),
686 ('hg.register.manual_activate', _('User Registration with manual account activation')),
688 ('hg.register.auto_activate', _('User Registration with automatic account activation')),
687 ('hg.register.auto_activate', _('User Registration with automatic account activation')),
689
688
690 ('hg.extern_activate.manual', _('Manual activation of external account')),
689 ('hg.extern_activate.manual', _('Manual activation of external account')),
691 ('hg.extern_activate.auto', _('Automatic activation of external account')),
690 ('hg.extern_activate.auto', _('Automatic activation of external account')),
692
691
693 ]
692 ]
694
693
695 #definition of system default permissions for DEFAULT user
694 #definition of system default permissions for DEFAULT user
696 DEFAULT_USER_PERMISSIONS = [
695 DEFAULT_USER_PERMISSIONS = [
697 'repository.read',
696 'repository.read',
698 'group.read',
697 'group.read',
699 'usergroup.read',
698 'usergroup.read',
700 'hg.create.repository',
699 'hg.create.repository',
701 'hg.fork.repository',
700 'hg.fork.repository',
702 'hg.register.manual_activate',
701 'hg.register.manual_activate',
703 'hg.extern_activate.auto',
702 'hg.extern_activate.auto',
704 ]
703 ]
705
704
706 # defines which permissions are more important higher the more important
705 # defines which permissions are more important higher the more important
707 # Weight defines which permissions are more important.
706 # Weight defines which permissions are more important.
708 # The higher number the more important.
707 # The higher number the more important.
709 PERM_WEIGHTS = {
708 PERM_WEIGHTS = {
710 'repository.none': 0,
709 'repository.none': 0,
711 'repository.read': 1,
710 'repository.read': 1,
712 'repository.write': 3,
711 'repository.write': 3,
713 'repository.admin': 4,
712 'repository.admin': 4,
714
713
715 'group.none': 0,
714 'group.none': 0,
716 'group.read': 1,
715 'group.read': 1,
717 'group.write': 3,
716 'group.write': 3,
718 'group.admin': 4,
717 'group.admin': 4,
719
718
720 'usergroup.none': 0,
719 'usergroup.none': 0,
721 'usergroup.read': 1,
720 'usergroup.read': 1,
722 'usergroup.write': 3,
721 'usergroup.write': 3,
723 'usergroup.admin': 4,
722 'usergroup.admin': 4,
724 'hg.repogroup.create.false': 0,
723 'hg.repogroup.create.false': 0,
725 'hg.repogroup.create.true': 1,
724 'hg.repogroup.create.true': 1,
726
725
727 'hg.usergroup.create.false': 0,
726 'hg.usergroup.create.false': 0,
728 'hg.usergroup.create.true': 1,
727 'hg.usergroup.create.true': 1,
729
728
730 'hg.fork.none': 0,
729 'hg.fork.none': 0,
731 'hg.fork.repository': 1,
730 'hg.fork.repository': 1,
732 'hg.create.none': 0,
731 'hg.create.none': 0,
733 'hg.create.repository': 1
732 'hg.create.repository': 1
734 }
733 }
735
734
736 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
735 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
737 permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None)
736 permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None)
738 permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None)
737 permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None)
739
738
740 def __unicode__(self):
739 def __unicode__(self):
741 return u"<%s('%s:%s')>" % (
740 return u"<%s('%s:%s')>" % (
742 self.__class__.__name__, self.permission_id, self.permission_name
741 self.__class__.__name__, self.permission_id, self.permission_name
743 )
742 )
744
743
745 @classmethod
744 @classmethod
746 def get_by_key(cls, key):
745 def get_by_key(cls, key):
747 return cls.query().filter(cls.permission_name == key).scalar()
746 return cls.query().filter(cls.permission_name == key).scalar()
748
747
749
748
750 class UserRepoToPerm(Base, BaseModel):
749 class UserRepoToPerm(Base, BaseModel):
751 __tablename__ = 'repo_to_perm'
750 __tablename__ = 'repo_to_perm'
752 __table_args__ = (
751 __table_args__ = (
753 UniqueConstraint('user_id', 'repository_id', 'permission_id'),
752 UniqueConstraint('user_id', 'repository_id', 'permission_id'),
754 {'extend_existing': True, 'mysql_engine': 'InnoDB',
753 {'extend_existing': True, 'mysql_engine': 'InnoDB',
755 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
754 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
756 )
755 )
757 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
756 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
758 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
757 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
759 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
758 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
760 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
759 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
761
760
762 user = relationship('User')
761 user = relationship('User')
763 repository = relationship('Repository')
762 repository = relationship('Repository')
764 permission = relationship('Permission')
763 permission = relationship('Permission')
765
764
766 def __unicode__(self):
765 def __unicode__(self):
767 return u'<%s => %s >' % (self.user, self.repository)
766 return u'<%s => %s >' % (self.user, self.repository)
768
767
769
768
770 class UserUserGroupToPerm(Base, BaseModel):
769 class UserUserGroupToPerm(Base, BaseModel):
771 __tablename__ = 'user_user_group_to_perm'
770 __tablename__ = 'user_user_group_to_perm'
772 __table_args__ = (
771 __table_args__ = (
773 UniqueConstraint('user_id', 'user_group_id', 'permission_id'),
772 UniqueConstraint('user_id', 'user_group_id', 'permission_id'),
774 {'extend_existing': True, 'mysql_engine': 'InnoDB',
773 {'extend_existing': True, 'mysql_engine': 'InnoDB',
775 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
774 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
776 )
775 )
777 user_user_group_to_perm_id = Column("user_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
776 user_user_group_to_perm_id = Column("user_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
778 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
777 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
779 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
778 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
780 user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
779 user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
781
780
782 user = relationship('User')
781 user = relationship('User')
783 user_group = relationship('UserGroup')
782 user_group = relationship('UserGroup')
784 permission = relationship('Permission')
783 permission = relationship('Permission')
785
784
786 def __unicode__(self):
785 def __unicode__(self):
787 return u'<%s => %s >' % (self.user, self.user_group)
786 return u'<%s => %s >' % (self.user, self.user_group)
788
787
789
788
790 class UserToPerm(Base, BaseModel):
789 class UserToPerm(Base, BaseModel):
791 __tablename__ = 'user_to_perm'
790 __tablename__ = 'user_to_perm'
792 __table_args__ = (
791 __table_args__ = (
793 UniqueConstraint('user_id', 'permission_id'),
792 UniqueConstraint('user_id', 'permission_id'),
794 {'extend_existing': True, 'mysql_engine': 'InnoDB',
793 {'extend_existing': True, 'mysql_engine': 'InnoDB',
795 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
794 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
796 )
795 )
797 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
796 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
798 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
797 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
799 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
798 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
800
799
801 user = relationship('User')
800 user = relationship('User')
802 permission = relationship('Permission', lazy='joined')
801 permission = relationship('Permission', lazy='joined')
803
802
804 def __unicode__(self):
803 def __unicode__(self):
805 return u'<%s => %s >' % (self.user, self.permission)
804 return u'<%s => %s >' % (self.user, self.permission)
806
805
807
806
808 class UserGroupRepoToPerm(Base, BaseModel):
807 class UserGroupRepoToPerm(Base, BaseModel):
809 __tablename__ = 'users_group_repo_to_perm'
808 __tablename__ = 'users_group_repo_to_perm'
810 __table_args__ = (
809 __table_args__ = (
811 UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
810 UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
812 {'extend_existing': True, 'mysql_engine': 'InnoDB',
811 {'extend_existing': True, 'mysql_engine': 'InnoDB',
813 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
812 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
814 )
813 )
815 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
814 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
816 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
815 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
817 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
816 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
818 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
817 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
819
818
820 users_group = relationship('UserGroup')
819 users_group = relationship('UserGroup')
821 permission = relationship('Permission')
820 permission = relationship('Permission')
822 repository = relationship('Repository')
821 repository = relationship('Repository')
823
822
824 def __unicode__(self):
823 def __unicode__(self):
825 return u'<UserGroupRepoToPerm:%s => %s >' % (self.users_group, self.repository)
824 return u'<UserGroupRepoToPerm:%s => %s >' % (self.users_group, self.repository)
826
825
827
826
828 class UserGroupUserGroupToPerm(Base, BaseModel):
827 class UserGroupUserGroupToPerm(Base, BaseModel):
829 __tablename__ = 'user_group_user_group_to_perm'
828 __tablename__ = 'user_group_user_group_to_perm'
830 __table_args__ = (
829 __table_args__ = (
831 UniqueConstraint('target_user_group_id', 'user_group_id', 'permission_id'),
830 UniqueConstraint('target_user_group_id', 'user_group_id', 'permission_id'),
832 CheckConstraint('target_user_group_id != user_group_id'),
831 CheckConstraint('target_user_group_id != user_group_id'),
833 {'extend_existing': True, 'mysql_engine': 'InnoDB',
832 {'extend_existing': True, 'mysql_engine': 'InnoDB',
834 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
833 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
835 )
834 )
836 user_group_user_group_to_perm_id = Column("user_group_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
835 user_group_user_group_to_perm_id = Column("user_group_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
837 target_user_group_id = Column("target_user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
836 target_user_group_id = Column("target_user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
838 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
837 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
839 user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
838 user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
840
839
841 target_user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id')
840 target_user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id')
842 user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.user_group_id==UserGroup.users_group_id')
841 user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.user_group_id==UserGroup.users_group_id')
843 permission = relationship('Permission')
842 permission = relationship('Permission')
844
843
845 def __unicode__(self):
844 def __unicode__(self):
846 return u'<UserGroupUserGroup:%s => %s >' % (self.target_user_group, self.user_group)
845 return u'<UserGroupUserGroup:%s => %s >' % (self.target_user_group, self.user_group)
847
846
848
847
849 class UserGroupToPerm(Base, BaseModel):
848 class UserGroupToPerm(Base, BaseModel):
850 __tablename__ = 'users_group_to_perm'
849 __tablename__ = 'users_group_to_perm'
851 __table_args__ = (
850 __table_args__ = (
852 UniqueConstraint('users_group_id', 'permission_id',),
851 UniqueConstraint('users_group_id', 'permission_id',),
853 {'extend_existing': True, 'mysql_engine': 'InnoDB',
852 {'extend_existing': True, 'mysql_engine': 'InnoDB',
854 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
853 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
855 )
854 )
856 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
855 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
857 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
856 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
858 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
857 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
859
858
860 users_group = relationship('UserGroup')
859 users_group = relationship('UserGroup')
861 permission = relationship('Permission')
860 permission = relationship('Permission')
862
861
863
862
864 class UserRepoGroupToPerm(Base, BaseModel):
863 class UserRepoGroupToPerm(Base, BaseModel):
865 __tablename__ = 'user_repo_group_to_perm'
864 __tablename__ = 'user_repo_group_to_perm'
866 __table_args__ = (
865 __table_args__ = (
867 UniqueConstraint('user_id', 'group_id', 'permission_id'),
866 UniqueConstraint('user_id', 'group_id', 'permission_id'),
868 {'extend_existing': True, 'mysql_engine': 'InnoDB',
867 {'extend_existing': True, 'mysql_engine': 'InnoDB',
869 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
868 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
870 )
869 )
871
870
872 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
871 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
873 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
872 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
874 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
873 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
875 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
874 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
876
875
877 user = relationship('User')
876 user = relationship('User')
878 group = relationship('RepoGroup')
877 group = relationship('RepoGroup')
879 permission = relationship('Permission')
878 permission = relationship('Permission')
880
879
881
880
882 class UserGroupRepoGroupToPerm(Base, BaseModel):
881 class UserGroupRepoGroupToPerm(Base, BaseModel):
883 __tablename__ = 'users_group_repo_group_to_perm'
882 __tablename__ = 'users_group_repo_group_to_perm'
884 __table_args__ = (
883 __table_args__ = (
885 UniqueConstraint('users_group_id', 'group_id'),
884 UniqueConstraint('users_group_id', 'group_id'),
886 {'extend_existing': True, 'mysql_engine': 'InnoDB',
885 {'extend_existing': True, 'mysql_engine': 'InnoDB',
887 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
886 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
888 )
887 )
889
888
890 users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
889 users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
891 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
890 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
892 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
891 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
893 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
892 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
894
893
895 users_group = relationship('UserGroup')
894 users_group = relationship('UserGroup')
896 permission = relationship('Permission')
895 permission = relationship('Permission')
897 group = relationship('RepoGroup')
896 group = relationship('RepoGroup')
898
897
899
898
900 class Statistics(Base, BaseModel):
899 class Statistics(Base, BaseModel):
901 __tablename__ = 'statistics'
900 __tablename__ = 'statistics'
902 __table_args__ = (
901 __table_args__ = (
903 UniqueConstraint('repository_id'),
902 UniqueConstraint('repository_id'),
904 {'extend_existing': True, 'mysql_engine': 'InnoDB',
903 {'extend_existing': True, 'mysql_engine': 'InnoDB',
905 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
904 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
906 )
905 )
907 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
906 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
908 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
907 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
909 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
908 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
910 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
909 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
911 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
910 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
912 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
911 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
913
912
914 repository = relationship('Repository', single_parent=True)
913 repository = relationship('Repository', single_parent=True)
915
914
916
915
917 class UserFollowing(Base, BaseModel):
916 class UserFollowing(Base, BaseModel):
918 __tablename__ = 'user_followings'
917 __tablename__ = 'user_followings'
919 __table_args__ = (
918 __table_args__ = (
920 UniqueConstraint('user_id', 'follows_repository_id'),
919 UniqueConstraint('user_id', 'follows_repository_id'),
921 UniqueConstraint('user_id', 'follows_user_id'),
920 UniqueConstraint('user_id', 'follows_user_id'),
922 {'extend_existing': True, 'mysql_engine': 'InnoDB',
921 {'extend_existing': True, 'mysql_engine': 'InnoDB',
923 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
922 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
924 )
923 )
925
924
926 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
925 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
927 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
926 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
928 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
927 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
929 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
928 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
930 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
929 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
931
930
932 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
931 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
933
932
934 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
933 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
935 follows_repository = relationship('Repository', order_by='Repository.repo_name')
934 follows_repository = relationship('Repository', order_by='Repository.repo_name')
936
935
937
936
938 class CacheInvalidation(Base, BaseModel):
937 class CacheInvalidation(Base, BaseModel):
939 __tablename__ = 'cache_invalidation'
938 __tablename__ = 'cache_invalidation'
940 __table_args__ = (
939 __table_args__ = (
941 UniqueConstraint('cache_key'),
940 UniqueConstraint('cache_key'),
942 Index('key_idx', 'cache_key'),
941 Index('key_idx', 'cache_key'),
943 {'extend_existing': True, 'mysql_engine': 'InnoDB',
942 {'extend_existing': True, 'mysql_engine': 'InnoDB',
944 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
943 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
945 )
944 )
946 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
945 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
947 cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None)
946 cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None)
948 cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None)
947 cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None)
949 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
948 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
950
949
951 def __init__(self, cache_key, cache_args=''):
950 def __init__(self, cache_key, cache_args=''):
952 self.cache_key = cache_key
951 self.cache_key = cache_key
953 self.cache_args = cache_args
952 self.cache_args = cache_args
954 self.cache_active = False
953 self.cache_active = False
955
954
956
955
957 class ChangesetComment(Base, BaseModel):
956 class ChangesetComment(Base, BaseModel):
958 __tablename__ = 'changeset_comments'
957 __tablename__ = 'changeset_comments'
959 __table_args__ = (
958 __table_args__ = (
960 Index('cc_revision_idx', 'revision'),
959 Index('cc_revision_idx', 'revision'),
961 {'extend_existing': True, 'mysql_engine': 'InnoDB',
960 {'extend_existing': True, 'mysql_engine': 'InnoDB',
962 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
961 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
963 )
962 )
964 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
963 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
965 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
964 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
966 revision = Column('revision', String(40), nullable=True)
965 revision = Column('revision', String(40), nullable=True)
967 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
966 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
968 line_no = Column('line_no', Unicode(10), nullable=True)
967 line_no = Column('line_no', Unicode(10), nullable=True)
969 hl_lines = Column('hl_lines', Unicode(512), nullable=True)
968 hl_lines = Column('hl_lines', Unicode(512), nullable=True)
970 f_path = Column('f_path', Unicode(1000), nullable=True)
969 f_path = Column('f_path', Unicode(1000), nullable=True)
971 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
970 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
972 text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False)
971 text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False)
973 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
972 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
974 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
973 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
975
974
976 author = relationship('User', lazy='joined')
975 author = relationship('User', lazy='joined')
977 repo = relationship('Repository')
976 repo = relationship('Repository')
978 status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan")
977 status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan")
979 pull_request = relationship('PullRequest', lazy='joined')
978 pull_request = relationship('PullRequest', lazy='joined')
980
979
981
980
982 class ChangesetStatus(Base, BaseModel):
981 class ChangesetStatus(Base, BaseModel):
983 __tablename__ = 'changeset_statuses'
982 __tablename__ = 'changeset_statuses'
984 __table_args__ = (
983 __table_args__ = (
985 Index('cs_revision_idx', 'revision'),
984 Index('cs_revision_idx', 'revision'),
986 Index('cs_version_idx', 'version'),
985 Index('cs_version_idx', 'version'),
987 UniqueConstraint('repo_id', 'revision', 'version'),
986 UniqueConstraint('repo_id', 'revision', 'version'),
988 {'extend_existing': True, 'mysql_engine': 'InnoDB',
987 {'extend_existing': True, 'mysql_engine': 'InnoDB',
989 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
988 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
990 )
989 )
991 STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed'
990 STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed'
992 STATUS_APPROVED = 'approved'
991 STATUS_APPROVED = 'approved'
993 STATUS_REJECTED = 'rejected'
992 STATUS_REJECTED = 'rejected'
994 STATUS_UNDER_REVIEW = 'under_review'
993 STATUS_UNDER_REVIEW = 'under_review'
995
994
996 STATUSES = [
995 STATUSES = [
997 (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default
996 (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default
998 (STATUS_APPROVED, _("Approved")),
997 (STATUS_APPROVED, _("Approved")),
999 (STATUS_REJECTED, _("Rejected")),
998 (STATUS_REJECTED, _("Rejected")),
1000 (STATUS_UNDER_REVIEW, _("Under Review")),
999 (STATUS_UNDER_REVIEW, _("Under Review")),
1001 ]
1000 ]
1002
1001
1003 changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True)
1002 changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True)
1004 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1003 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1005 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1004 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1006 revision = Column('revision', String(40), nullable=False)
1005 revision = Column('revision', String(40), nullable=False)
1007 status = Column('status', String(128), nullable=False, default=DEFAULT)
1006 status = Column('status', String(128), nullable=False, default=DEFAULT)
1008 changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id'))
1007 changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id'))
1009 modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
1008 modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
1010 version = Column('version', Integer(), nullable=False, default=0)
1009 version = Column('version', Integer(), nullable=False, default=0)
1011 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
1010 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
1012
1011
1013 author = relationship('User', lazy='joined')
1012 author = relationship('User', lazy='joined')
1014 repo = relationship('Repository')
1013 repo = relationship('Repository')
1015 comment = relationship('ChangesetComment', lazy='joined')
1014 comment = relationship('ChangesetComment', lazy='joined')
1016 pull_request = relationship('PullRequest', lazy='joined')
1015 pull_request = relationship('PullRequest', lazy='joined')
1017
1016
1018
1017
1019
1018
1020 class PullRequest(Base, BaseModel):
1019 class PullRequest(Base, BaseModel):
1021 __tablename__ = 'pull_requests'
1020 __tablename__ = 'pull_requests'
1022 __table_args__ = (
1021 __table_args__ = (
1023 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1022 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1024 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1023 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1025 )
1024 )
1026
1025
1027 STATUS_NEW = u'new'
1026 STATUS_NEW = u'new'
1028 STATUS_OPEN = u'open'
1027 STATUS_OPEN = u'open'
1029 STATUS_CLOSED = u'closed'
1028 STATUS_CLOSED = u'closed'
1030
1029
1031 pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True)
1030 pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True)
1032 title = Column('title', Unicode(256), nullable=True)
1031 title = Column('title', Unicode(256), nullable=True)
1033 description = Column('description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), nullable=True)
1032 description = Column('description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), nullable=True)
1034 status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW)
1033 status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW)
1035 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1034 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1036 updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1035 updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1037 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1036 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1038 _revisions = Column('revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql'))
1037 _revisions = Column('revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql'))
1039 org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1038 org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1040 org_ref = Column('org_ref', Unicode(256), nullable=False)
1039 org_ref = Column('org_ref', Unicode(256), nullable=False)
1041 other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1040 other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1042 other_ref = Column('other_ref', Unicode(256), nullable=False)
1041 other_ref = Column('other_ref', Unicode(256), nullable=False)
1043
1042
1044 author = relationship('User', lazy='joined')
1043 author = relationship('User', lazy='joined')
1045 reviewers = relationship('PullRequestReviewers',
1044 reviewers = relationship('PullRequestReviewers',
1046 cascade="all, delete, delete-orphan")
1045 cascade="all, delete, delete-orphan")
1047 org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id')
1046 org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id')
1048 other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id')
1047 other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id')
1049 statuses = relationship('ChangesetStatus')
1048 statuses = relationship('ChangesetStatus')
1050 comments = relationship('ChangesetComment',
1049 comments = relationship('ChangesetComment',
1051 cascade="all, delete, delete-orphan")
1050 cascade="all, delete, delete-orphan")
1052
1051
1053
1052
1054 class PullRequestReviewers(Base, BaseModel):
1053 class PullRequestReviewers(Base, BaseModel):
1055 __tablename__ = 'pull_request_reviewers'
1054 __tablename__ = 'pull_request_reviewers'
1056 __table_args__ = (
1055 __table_args__ = (
1057 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1056 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1058 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1057 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1059 )
1058 )
1060
1059
1061 def __init__(self, user=None, pull_request=None):
1060 def __init__(self, user=None, pull_request=None):
1062 self.user = user
1061 self.user = user
1063 self.pull_request = pull_request
1062 self.pull_request = pull_request
1064
1063
1065 pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True)
1064 pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True)
1066 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False)
1065 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False)
1067 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True)
1066 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True)
1068
1067
1069 user = relationship('User')
1068 user = relationship('User')
1070 pull_request = relationship('PullRequest')
1069 pull_request = relationship('PullRequest')
1071
1070
1072
1071
1073 class Notification(Base, BaseModel):
1072 class Notification(Base, BaseModel):
1074 __tablename__ = 'notifications'
1073 __tablename__ = 'notifications'
1075 __table_args__ = (
1074 __table_args__ = (
1076 Index('notification_type_idx', 'type'),
1075 Index('notification_type_idx', 'type'),
1077 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1076 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1078 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1077 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1079 )
1078 )
1080
1079
1081 TYPE_CHANGESET_COMMENT = u'cs_comment'
1080 TYPE_CHANGESET_COMMENT = u'cs_comment'
1082 TYPE_MESSAGE = u'message'
1081 TYPE_MESSAGE = u'message'
1083 TYPE_MENTION = u'mention'
1082 TYPE_MENTION = u'mention'
1084 TYPE_REGISTRATION = u'registration'
1083 TYPE_REGISTRATION = u'registration'
1085 TYPE_PULL_REQUEST = u'pull_request'
1084 TYPE_PULL_REQUEST = u'pull_request'
1086 TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment'
1085 TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment'
1087
1086
1088 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
1087 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
1089 subject = Column('subject', Unicode(512), nullable=True)
1088 subject = Column('subject', Unicode(512), nullable=True)
1090 body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True)
1089 body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True)
1091 created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
1090 created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
1092 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1091 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1093 type_ = Column('type', Unicode(256))
1092 type_ = Column('type', Unicode(256))
1094
1093
1095 created_by_user = relationship('User')
1094 created_by_user = relationship('User')
1096 notifications_to_users = relationship('UserNotification', lazy='joined',
1095 notifications_to_users = relationship('UserNotification', lazy='joined',
1097 cascade="all, delete, delete-orphan")
1096 cascade="all, delete, delete-orphan")
1098
1097
1099
1098
1100 class UserNotification(Base, BaseModel):
1099 class UserNotification(Base, BaseModel):
1101 __tablename__ = 'user_to_notification'
1100 __tablename__ = 'user_to_notification'
1102 __table_args__ = (
1101 __table_args__ = (
1103 UniqueConstraint('user_id', 'notification_id'),
1102 UniqueConstraint('user_id', 'notification_id'),
1104 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1103 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1105 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1104 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1106 )
1105 )
1107 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
1106 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
1108 notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
1107 notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
1109 read = Column('read', Boolean, default=False)
1108 read = Column('read', Boolean, default=False)
1110 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
1109 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
1111
1110
1112 user = relationship('User', lazy="joined")
1111 user = relationship('User', lazy="joined")
1113 notification = relationship('Notification', lazy="joined",
1112 notification = relationship('Notification', lazy="joined",
1114 order_by=lambda: Notification.created_on.desc(),)
1113 order_by=lambda: Notification.created_on.desc(),)
1115
1114
1116
1115
1117 class Gist(Base, BaseModel):
1116 class Gist(Base, BaseModel):
1118 __tablename__ = 'gists'
1117 __tablename__ = 'gists'
1119 __table_args__ = (
1118 __table_args__ = (
1120 Index('g_gist_access_id_idx', 'gist_access_id'),
1119 Index('g_gist_access_id_idx', 'gist_access_id'),
1121 Index('g_created_on_idx', 'created_on'),
1120 Index('g_created_on_idx', 'created_on'),
1122 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1121 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1123 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1122 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1124 )
1123 )
1125 GIST_PUBLIC = u'public'
1124 GIST_PUBLIC = u'public'
1126 GIST_PRIVATE = u'private'
1125 GIST_PRIVATE = u'private'
1127
1126
1128 gist_id = Column('gist_id', Integer(), primary_key=True)
1127 gist_id = Column('gist_id', Integer(), primary_key=True)
1129 gist_access_id = Column('gist_access_id', Unicode(250))
1128 gist_access_id = Column('gist_access_id', Unicode(250))
1130 gist_description = Column('gist_description', UnicodeText().with_variant(UnicodeText(1024), 'mysql'))
1129 gist_description = Column('gist_description', UnicodeText().with_variant(UnicodeText(1024), 'mysql'))
1131 gist_owner = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=True)
1130 gist_owner = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=True)
1132 gist_expires = Column('gist_expires', Float(53), nullable=False)
1131 gist_expires = Column('gist_expires', Float(53), nullable=False)
1133 gist_type = Column('gist_type', Unicode(128), nullable=False)
1132 gist_type = Column('gist_type', Unicode(128), nullable=False)
1134 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1133 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1135 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1134 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1136
1135
1137 owner = relationship('User')
1136 owner = relationship('User')
1138
1137
1139
1138
1140 class DbMigrateVersion(Base, BaseModel):
1139 class DbMigrateVersion(Base, BaseModel):
1141 __tablename__ = 'db_migrate_version'
1140 __tablename__ = 'db_migrate_version'
1142 __table_args__ = (
1141 __table_args__ = (
1143 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1142 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1144 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1143 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1145 )
1144 )
1146 repository_id = Column('repository_id', String(250), primary_key=True)
1145 repository_id = Column('repository_id', String(250), primary_key=True)
1147 repository_path = Column('repository_path', Text)
1146 repository_path = Column('repository_path', Text)
1148 version = Column('version', Integer)
1147 version = Column('version', Integer)
@@ -1,1171 +1,1170 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2019 RhodeCode GmbH
3 # Copyright (C) 2010-2019 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import os
21 import os
22 import time
22 import time
23 import logging
23 import logging
24 import datetime
24 import datetime
25 import traceback
25 import traceback
26 import hashlib
26 import hashlib
27 import collections
27 import collections
28 import functools
28 import functools
29
29
30 from sqlalchemy import *
30 from sqlalchemy import *
31 from sqlalchemy.ext.hybrid import hybrid_property
31 from sqlalchemy.ext.hybrid import hybrid_property
32 from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
32 from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
33 from sqlalchemy.exc import DatabaseError
33 from sqlalchemy.exc import DatabaseError
34 from beaker.cache import cache_region, region_invalidate
34 from beaker.cache import cache_region, region_invalidate
35 from webob.exc import HTTPNotFound
35 from webob.exc import HTTPNotFound
36
36
37 from rhodecode.translation import _
37 from rhodecode.translation import _
38
38
39 from rhodecode.lib.vcs import get_backend
39 from rhodecode.lib.vcs import get_backend
40 from rhodecode.lib.vcs.utils.helpers import get_scm
40 from rhodecode.lib.vcs.utils.helpers import get_scm
41 from rhodecode.lib.vcs.exceptions import VCSError
41 from rhodecode.lib.vcs.exceptions import VCSError
42 from zope.cachedescriptors.property import Lazy as LazyProperty
42 from zope.cachedescriptors.property import Lazy as LazyProperty
43 from rhodecode.lib.vcs.backends.base import EmptyCommit
43 from rhodecode.lib.vcs.backends.base import EmptyCommit
44
44
45 from rhodecode.lib.utils2 import str2bool, safe_str, get_commit_safe, \
45 from rhodecode.lib.utils2 import str2bool, safe_str, get_commit_safe, \
46 safe_unicode, remove_prefix, time_to_datetime, aslist, Optional, safe_int
46 safe_unicode, remove_prefix, time_to_datetime, aslist, Optional, safe_int
47 from rhodecode.lib.ext_json import json
47 from rhodecode.lib.ext_json import json
48 from rhodecode.lib.caching_query import FromCache
48 from rhodecode.lib.caching_query import FromCache
49
49
50 from rhodecode.model.meta import Base, Session
50 from rhodecode.model.meta import Base, Session
51
51
52 URL_SEP = '/'
52 URL_SEP = '/'
53 log = logging.getLogger(__name__)
53 log = logging.getLogger(__name__)
54
54
55 #==============================================================================
55 #==============================================================================
56 # BASE CLASSES
56 # BASE CLASSES
57 #==============================================================================
57 #==============================================================================
58
58
59 _hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest()
59 _hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest()
60
60
61
61
62 class BaseModel(object):
62 class BaseModel(object):
63 """
63 """
64 Base Model for all classes
64 Base Model for all classes
65 """
65 """
66
66
67 @classmethod
67 @classmethod
68 def _get_keys(cls):
68 def _get_keys(cls):
69 """return column names for this model """
69 """return column names for this model """
70 return class_mapper(cls).c.keys()
70 return class_mapper(cls).c.keys()
71
71
72 def get_dict(self):
72 def get_dict(self):
73 """
73 """
74 return dict with keys and values corresponding
74 return dict with keys and values corresponding
75 to this model data """
75 to this model data """
76
76
77 d = {}
77 d = {}
78 for k in self._get_keys():
78 for k in self._get_keys():
79 d[k] = getattr(self, k)
79 d[k] = getattr(self, k)
80
80
81 # also use __json__() if present to get additional fields
81 # also use __json__() if present to get additional fields
82 _json_attr = getattr(self, '__json__', None)
82 _json_attr = getattr(self, '__json__', None)
83 if _json_attr:
83 if _json_attr:
84 # update with attributes from __json__
84 # update with attributes from __json__
85 if callable(_json_attr):
85 if callable(_json_attr):
86 _json_attr = _json_attr()
86 _json_attr = _json_attr()
87 for k, val in _json_attr.iteritems():
87 for k, val in _json_attr.iteritems():
88 d[k] = val
88 d[k] = val
89 return d
89 return d
90
90
91 def get_appstruct(self):
91 def get_appstruct(self):
92 """return list with keys and values tupples corresponding
92 """return list with keys and values tupples corresponding
93 to this model data """
93 to this model data """
94
94
95 l = []
95 l = []
96 for k in self._get_keys():
96 for k in self._get_keys():
97 l.append((k, getattr(self, k),))
97 l.append((k, getattr(self, k),))
98 return l
98 return l
99
99
100 def populate_obj(self, populate_dict):
100 def populate_obj(self, populate_dict):
101 """populate model with data from given populate_dict"""
101 """populate model with data from given populate_dict"""
102
102
103 for k in self._get_keys():
103 for k in self._get_keys():
104 if k in populate_dict:
104 if k in populate_dict:
105 setattr(self, k, populate_dict[k])
105 setattr(self, k, populate_dict[k])
106
106
107 @classmethod
107 @classmethod
108 def query(cls):
108 def query(cls):
109 return Session().query(cls)
109 return Session().query(cls)
110
110
111 @classmethod
111 @classmethod
112 def get(cls, id_):
112 def get(cls, id_):
113 if id_:
113 if id_:
114 return cls.query().get(id_)
114 return cls.query().get(id_)
115
115
116 @classmethod
116 @classmethod
117 def get_or_404(cls, id_):
117 def get_or_404(cls, id_):
118 try:
118 try:
119 id_ = int(id_)
119 id_ = int(id_)
120 except (TypeError, ValueError):
120 except (TypeError, ValueError):
121 raise HTTPNotFound
121 raise HTTPNotFound
122
122
123 res = cls.query().get(id_)
123 res = cls.query().get(id_)
124 if not res:
124 if not res:
125 raise HTTPNotFound
125 raise HTTPNotFound
126 return res
126 return res
127
127
128 @classmethod
128 @classmethod
129 def getAll(cls):
129 def getAll(cls):
130 # deprecated and left for backward compatibility
130 # deprecated and left for backward compatibility
131 return cls.get_all()
131 return cls.get_all()
132
132
133 @classmethod
133 @classmethod
134 def get_all(cls):
134 def get_all(cls):
135 return cls.query().all()
135 return cls.query().all()
136
136
137 @classmethod
137 @classmethod
138 def delete(cls, id_):
138 def delete(cls, id_):
139 obj = cls.query().get(id_)
139 obj = cls.query().get(id_)
140 Session().delete(obj)
140 Session().delete(obj)
141
141
142 def __repr__(self):
142 def __repr__(self):
143 if hasattr(self, '__unicode__'):
143 if hasattr(self, '__unicode__'):
144 # python repr needs to return str
144 # python repr needs to return str
145 return safe_str(self.__unicode__())
145 return safe_str(self.__unicode__())
146 return '<DB:%s>' % (self.__class__.__name__)
146 return '<DB:%s>' % (self.__class__.__name__)
147
147
148
148
149 class RhodeCodeSetting(Base, BaseModel):
149 class RhodeCodeSetting(Base, BaseModel):
150 SETTINGS_TYPES = {
150 SETTINGS_TYPES = {
151 'str': safe_str,
151 'str': safe_str,
152 'int': safe_int,
152 'int': safe_int,
153 'unicode': safe_unicode,
153 'unicode': safe_unicode,
154 'bool': str2bool,
154 'bool': str2bool,
155 'list': functools.partial(aslist, sep=',')
155 'list': functools.partial(aslist, sep=',')
156 }
156 }
157 __tablename__ = 'rhodecode_settings'
157 __tablename__ = 'rhodecode_settings'
158 __table_args__ = (
158 __table_args__ = (
159 UniqueConstraint('app_settings_name'),
159 UniqueConstraint('app_settings_name'),
160 {'extend_existing': True, 'mysql_engine': 'InnoDB',
160 {'extend_existing': True, 'mysql_engine': 'InnoDB',
161 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
161 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
162 )
162 )
163 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
163 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
164 app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None)
164 app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None)
165 _app_settings_value = Column("app_settings_value", String(4096), nullable=True, unique=None, default=None)
165 _app_settings_value = Column("app_settings_value", String(4096), nullable=True, unique=None, default=None)
166 _app_settings_type = Column("app_settings_type", String(255), nullable=True, unique=None, default=None)
166 _app_settings_type = Column("app_settings_type", String(255), nullable=True, unique=None, default=None)
167
167
168 def __init__(self, key='', val='', type='unicode'):
168 def __init__(self, key='', val='', type='unicode'):
169 self.app_settings_name = key
169 self.app_settings_name = key
170 self.app_settings_value = val
170 self.app_settings_value = val
171 self.app_settings_type = type
171 self.app_settings_type = type
172
172
173 @validates('_app_settings_value')
173 @validates('_app_settings_value')
174 def validate_settings_value(self, key, val):
174 def validate_settings_value(self, key, val):
175 assert type(val) == unicode
175 assert type(val) == unicode
176 return val
176 return val
177
177
178 @hybrid_property
178 @hybrid_property
179 def app_settings_value(self):
179 def app_settings_value(self):
180 v = self._app_settings_value
180 v = self._app_settings_value
181 _type = self.app_settings_type
181 _type = self.app_settings_type
182 converter = self.SETTINGS_TYPES.get(_type) or self.SETTINGS_TYPES['unicode']
182 converter = self.SETTINGS_TYPES.get(_type) or self.SETTINGS_TYPES['unicode']
183 return converter(v)
183 return converter(v)
184
184
185 @app_settings_value.setter
185 @app_settings_value.setter
186 def app_settings_value(self, val):
186 def app_settings_value(self, val):
187 """
187 """
188 Setter that will always make sure we use unicode in app_settings_value
188 Setter that will always make sure we use unicode in app_settings_value
189
189
190 :param val:
190 :param val:
191 """
191 """
192 self._app_settings_value = safe_unicode(val)
192 self._app_settings_value = safe_unicode(val)
193
193
194 @hybrid_property
194 @hybrid_property
195 def app_settings_type(self):
195 def app_settings_type(self):
196 return self._app_settings_type
196 return self._app_settings_type
197
197
198 @app_settings_type.setter
198 @app_settings_type.setter
199 def app_settings_type(self, val):
199 def app_settings_type(self, val):
200 if val not in self.SETTINGS_TYPES:
200 if val not in self.SETTINGS_TYPES:
201 raise Exception('type must be one of %s got %s'
201 raise Exception('type must be one of %s got %s'
202 % (self.SETTINGS_TYPES.keys(), val))
202 % (self.SETTINGS_TYPES.keys(), val))
203 self._app_settings_type = val
203 self._app_settings_type = val
204
204
205 def __unicode__(self):
205 def __unicode__(self):
206 return u"<%s('%s:%s[%s]')>" % (
206 return u"<%s('%s:%s[%s]')>" % (
207 self.__class__.__name__,
207 self.__class__.__name__,
208 self.app_settings_name, self.app_settings_value, self.app_settings_type
208 self.app_settings_name, self.app_settings_value, self.app_settings_type
209 )
209 )
210
210
211
211
212 class RhodeCodeUi(Base, BaseModel):
212 class RhodeCodeUi(Base, BaseModel):
213 __tablename__ = 'rhodecode_ui'
213 __tablename__ = 'rhodecode_ui'
214 __table_args__ = (
214 __table_args__ = (
215 UniqueConstraint('ui_key'),
215 UniqueConstraint('ui_key'),
216 {'extend_existing': True, 'mysql_engine': 'InnoDB',
216 {'extend_existing': True, 'mysql_engine': 'InnoDB',
217 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
217 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
218 )
218 )
219
219
220 HOOK_REPO_SIZE = 'changegroup.repo_size'
220 HOOK_REPO_SIZE = 'changegroup.repo_size'
221 HOOK_PUSH = 'changegroup.push_logger'
221 HOOK_PUSH = 'changegroup.push_logger'
222 HOOK_PRE_PUSH = 'prechangegroup.pre_push'
222 HOOK_PRE_PUSH = 'prechangegroup.pre_push'
223 HOOK_PULL = 'outgoing.pull_logger'
223 HOOK_PULL = 'outgoing.pull_logger'
224 HOOK_PRE_PULL = 'preoutgoing.pre_pull'
224 HOOK_PRE_PULL = 'preoutgoing.pre_pull'
225
225
226 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
226 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
227 ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None)
227 ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None)
228 ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None)
228 ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None)
229 ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None)
229 ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None)
230 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
230 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
231
231
232
232
233
233
234 class User(Base, BaseModel):
234 class User(Base, BaseModel):
235 __tablename__ = 'users'
235 __tablename__ = 'users'
236 __table_args__ = (
236 __table_args__ = (
237 UniqueConstraint('username'), UniqueConstraint('email'),
237 UniqueConstraint('username'), UniqueConstraint('email'),
238 Index('u_username_idx', 'username'),
238 Index('u_username_idx', 'username'),
239 Index('u_email_idx', 'email'),
239 Index('u_email_idx', 'email'),
240 {'extend_existing': True, 'mysql_engine': 'InnoDB',
240 {'extend_existing': True, 'mysql_engine': 'InnoDB',
241 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
241 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
242 )
242 )
243 DEFAULT_USER = 'default'
243 DEFAULT_USER = 'default'
244
244
245 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
245 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
246 username = Column("username", String(255), nullable=True, unique=None, default=None)
246 username = Column("username", String(255), nullable=True, unique=None, default=None)
247 password = Column("password", String(255), nullable=True, unique=None, default=None)
247 password = Column("password", String(255), nullable=True, unique=None, default=None)
248 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
248 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
249 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
249 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
250 name = Column("firstname", String(255), nullable=True, unique=None, default=None)
250 name = Column("firstname", String(255), nullable=True, unique=None, default=None)
251 lastname = Column("lastname", String(255), nullable=True, unique=None, default=None)
251 lastname = Column("lastname", String(255), nullable=True, unique=None, default=None)
252 _email = Column("email", String(255), nullable=True, unique=None, default=None)
252 _email = Column("email", String(255), nullable=True, unique=None, default=None)
253 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
253 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
254 extern_type = Column("extern_type", String(255), nullable=True, unique=None, default=None)
254 extern_type = Column("extern_type", String(255), nullable=True, unique=None, default=None)
255 extern_name = Column("extern_name", String(255), nullable=True, unique=None, default=None)
255 extern_name = Column("extern_name", String(255), nullable=True, unique=None, default=None)
256 #for migration reasons, this is going to be later deleted
256 #for migration reasons, this is going to be later deleted
257 ldap_dn = Column("ldap_dn", String(255), nullable=True, unique=None, default=None)
257 ldap_dn = Column("ldap_dn", String(255), nullable=True, unique=None, default=None)
258
258
259 api_key = Column("api_key", String(255), nullable=True, unique=None, default=None)
259 api_key = Column("api_key", String(255), nullable=True, unique=None, default=None)
260 inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
260 inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
261 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
261 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
262
262
263 user_log = relationship('UserLog')
263 user_log = relationship('UserLog')
264 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
264 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
265
265
266 repositories = relationship('Repository')
266 repositories = relationship('Repository')
267 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
267 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
268 followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all')
268 followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all')
269
269
270 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
270 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
271 repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all')
271 repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all')
272
272
273 group_member = relationship('UserGroupMember', cascade='all')
273 group_member = relationship('UserGroupMember', cascade='all')
274
274
275 notifications = relationship('UserNotification', cascade='all')
275 notifications = relationship('UserNotification', cascade='all')
276 # notifications assigned to this user
276 # notifications assigned to this user
277 user_created_notifications = relationship('Notification', cascade='all')
277 user_created_notifications = relationship('Notification', cascade='all')
278 # comments created by this user
278 # comments created by this user
279 user_comments = relationship('ChangesetComment', cascade='all')
279 user_comments = relationship('ChangesetComment', cascade='all')
280 user_emails = relationship('UserEmailMap', cascade='all')
280 user_emails = relationship('UserEmailMap', cascade='all')
281
281
282 @hybrid_property
282 @hybrid_property
283 def email(self):
283 def email(self):
284 return self._email
284 return self._email
285
285
286 @email.setter
286 @email.setter
287 def email(self, val):
287 def email(self, val):
288 self._email = val.lower() if val else None
288 self._email = val.lower() if val else None
289
289
290 @property
290 @property
291 def firstname(self):
291 def firstname(self):
292 # alias for future
292 # alias for future
293 return self.name
293 return self.name
294
294
295 @property
295 @property
296 def username_and_name(self):
296 def username_and_name(self):
297 return '%s (%s %s)' % (self.username, self.firstname, self.lastname)
297 return '%s (%s %s)' % (self.username, self.firstname, self.lastname)
298
298
299 @property
299 @property
300 def full_name(self):
300 def full_name(self):
301 return '%s %s' % (self.firstname, self.lastname)
301 return '%s %s' % (self.firstname, self.lastname)
302
302
303 @property
303 @property
304 def full_contact(self):
304 def full_contact(self):
305 return '%s %s <%s>' % (self.firstname, self.lastname, self.email)
305 return '%s %s <%s>' % (self.firstname, self.lastname, self.email)
306
306
307 @property
307 @property
308 def short_contact(self):
308 def short_contact(self):
309 return '%s %s' % (self.firstname, self.lastname)
309 return '%s %s' % (self.firstname, self.lastname)
310
310
311 @property
311 @property
312 def is_admin(self):
312 def is_admin(self):
313 return self.admin
313 return self.admin
314
314
315 @classmethod
315 @classmethod
316 def get_by_username(cls, username, case_insensitive=False, cache=False):
316 def get_by_username(cls, username, case_insensitive=False, cache=False):
317 if case_insensitive:
317 if case_insensitive:
318 q = cls.query().filter(cls.username.ilike(username))
318 q = cls.query().filter(cls.username.ilike(username))
319 else:
319 else:
320 q = cls.query().filter(cls.username == username)
320 q = cls.query().filter(cls.username == username)
321
321
322 if cache:
322 if cache:
323 q = q.options(FromCache(
323 q = q.options(FromCache(
324 "sql_cache_short",
324 "sql_cache_short",
325 "get_user_%s" % _hash_key(username)
325 "get_user_%s" % _hash_key(username)
326 )
326 )
327 )
327 )
328 return q.scalar()
328 return q.scalar()
329
329
330 @classmethod
330 @classmethod
331 def get_by_auth_token(cls, auth_token, cache=False):
331 def get_by_auth_token(cls, auth_token, cache=False):
332 q = cls.query().filter(cls.api_key == auth_token)
332 q = cls.query().filter(cls.api_key == auth_token)
333
333
334 if cache:
334 if cache:
335 q = q.options(FromCache("sql_cache_short",
335 q = q.options(FromCache("sql_cache_short",
336 "get_auth_token_%s" % auth_token))
336 "get_auth_token_%s" % auth_token))
337 return q.scalar()
337 return q.scalar()
338
338
339 @classmethod
339 @classmethod
340 def get_by_email(cls, email, case_insensitive=False, cache=False):
340 def get_by_email(cls, email, case_insensitive=False, cache=False):
341 if case_insensitive:
341 if case_insensitive:
342 q = cls.query().filter(cls.email.ilike(email))
342 q = cls.query().filter(cls.email.ilike(email))
343 else:
343 else:
344 q = cls.query().filter(cls.email == email)
344 q = cls.query().filter(cls.email == email)
345
345
346 if cache:
346 if cache:
347 q = q.options(FromCache("sql_cache_short",
347 q = q.options(FromCache("sql_cache_short",
348 "get_email_key_%s" % email))
348 "get_email_key_%s" % email))
349
349
350 ret = q.scalar()
350 ret = q.scalar()
351 if ret is None:
351 if ret is None:
352 q = UserEmailMap.query()
352 q = UserEmailMap.query()
353 # try fetching in alternate email map
353 # try fetching in alternate email map
354 if case_insensitive:
354 if case_insensitive:
355 q = q.filter(UserEmailMap.email.ilike(email))
355 q = q.filter(UserEmailMap.email.ilike(email))
356 else:
356 else:
357 q = q.filter(UserEmailMap.email == email)
357 q = q.filter(UserEmailMap.email == email)
358 q = q.options(joinedload(UserEmailMap.user))
358 q = q.options(joinedload(UserEmailMap.user))
359 if cache:
359 if cache:
360 q = q.options(FromCache("sql_cache_short",
360 q = q.options(FromCache("sql_cache_short",
361 "get_email_map_key_%s" % email))
361 "get_email_map_key_%s" % email))
362 ret = getattr(q.scalar(), 'user', None)
362 ret = getattr(q.scalar(), 'user', None)
363
363
364 return ret
364 return ret
365
365
366 @classmethod
366 @classmethod
367 def get_first_admin(cls):
367 def get_first_admin(cls):
368 user = User.query().filter(User.admin == True).first()
368 user = User.query().filter(User.admin == True).first()
369 if user is None:
369 if user is None:
370 raise Exception('Missing administrative account!')
370 raise Exception('Missing administrative account!')
371 return user
371 return user
372
372
373 @classmethod
373 @classmethod
374 def get_default_user(cls, cache=False):
374 def get_default_user(cls, cache=False):
375 user = User.get_by_username(User.DEFAULT_USER, cache=cache)
375 user = User.get_by_username(User.DEFAULT_USER, cache=cache)
376 if user is None:
376 if user is None:
377 raise Exception('Missing default account!')
377 raise Exception('Missing default account!')
378 return user
378 return user
379
379
380
380
381
381
382
382
383 class UserEmailMap(Base, BaseModel):
383 class UserEmailMap(Base, BaseModel):
384 __tablename__ = 'user_email_map'
384 __tablename__ = 'user_email_map'
385 __table_args__ = (
385 __table_args__ = (
386 Index('uem_email_idx', 'email'),
386 Index('uem_email_idx', 'email'),
387 UniqueConstraint('email'),
387 UniqueConstraint('email'),
388 {'extend_existing': True, 'mysql_engine': 'InnoDB',
388 {'extend_existing': True, 'mysql_engine': 'InnoDB',
389 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
389 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
390 )
390 )
391 __mapper_args__ = {}
391 __mapper_args__ = {}
392
392
393 email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
393 email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
394 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
394 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
395 _email = Column("email", String(255), nullable=True, unique=False, default=None)
395 _email = Column("email", String(255), nullable=True, unique=False, default=None)
396 user = relationship('User', lazy='joined')
396 user = relationship('User', lazy='joined')
397
397
398 @validates('_email')
398 @validates('_email')
399 def validate_email(self, key, email):
399 def validate_email(self, key, email):
400 # check if this email is not main one
400 # check if this email is not main one
401 main_email = Session().query(User).filter(User.email == email).scalar()
401 main_email = Session().query(User).filter(User.email == email).scalar()
402 if main_email is not None:
402 if main_email is not None:
403 raise AttributeError('email %s is present is user table' % email)
403 raise AttributeError('email %s is present is user table' % email)
404 return email
404 return email
405
405
406 @hybrid_property
406 @hybrid_property
407 def email(self):
407 def email(self):
408 return self._email
408 return self._email
409
409
410 @email.setter
410 @email.setter
411 def email(self, val):
411 def email(self, val):
412 self._email = val.lower() if val else None
412 self._email = val.lower() if val else None
413
413
414
414
415 class UserIpMap(Base, BaseModel):
415 class UserIpMap(Base, BaseModel):
416 __tablename__ = 'user_ip_map'
416 __tablename__ = 'user_ip_map'
417 __table_args__ = (
417 __table_args__ = (
418 UniqueConstraint('user_id', 'ip_addr'),
418 UniqueConstraint('user_id', 'ip_addr'),
419 {'extend_existing': True, 'mysql_engine': 'InnoDB',
419 {'extend_existing': True, 'mysql_engine': 'InnoDB',
420 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
420 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
421 )
421 )
422 __mapper_args__ = {}
422 __mapper_args__ = {}
423
423
424 ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
424 ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
425 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
425 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
426 ip_addr = Column("ip_addr", String(255), nullable=True, unique=False, default=None)
426 ip_addr = Column("ip_addr", String(255), nullable=True, unique=False, default=None)
427 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
427 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
428 user = relationship('User', lazy='joined')
428 user = relationship('User', lazy='joined')
429
429
430
430
431 class UserLog(Base, BaseModel):
431 class UserLog(Base, BaseModel):
432 __tablename__ = 'user_logs'
432 __tablename__ = 'user_logs'
433 __table_args__ = (
433 __table_args__ = (
434 {'extend_existing': True, 'mysql_engine': 'InnoDB',
434 {'extend_existing': True, 'mysql_engine': 'InnoDB',
435 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
435 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
436 )
436 )
437 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
437 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
438 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
438 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
439 username = Column("username", String(255), nullable=True, unique=None, default=None)
439 username = Column("username", String(255), nullable=True, unique=None, default=None)
440 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
440 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
441 repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None)
441 repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None)
442 user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None)
442 user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None)
443 action = Column("action", String(1200000), nullable=True, unique=None, default=None)
443 action = Column("action", String(1200000), nullable=True, unique=None, default=None)
444 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
444 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
445
445
446 def __unicode__(self):
446 def __unicode__(self):
447 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
447 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
448 self.repository_name,
448 self.repository_name,
449 self.action)
449 self.action)
450
450
451 user = relationship('User')
451 user = relationship('User')
452 repository = relationship('Repository', cascade='')
452 repository = relationship('Repository', cascade='')
453
453
454
454
455 class UserGroup(Base, BaseModel):
455 class UserGroup(Base, BaseModel):
456 __tablename__ = 'users_groups'
456 __tablename__ = 'users_groups'
457 __table_args__ = (
457 __table_args__ = (
458 {'extend_existing': True, 'mysql_engine': 'InnoDB',
458 {'extend_existing': True, 'mysql_engine': 'InnoDB',
459 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
459 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
460 )
460 )
461
461
462 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
462 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
463 users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None)
463 users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None)
464 user_group_description = Column("user_group_description", String(10000), nullable=True, unique=None, default=None)
464 user_group_description = Column("user_group_description", String(10000), nullable=True, unique=None, default=None)
465 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
465 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
466 inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
466 inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
467 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
467 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
468 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
468 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
469
469
470 # don't trigger lazy load for migrations
470 # don't trigger lazy load for migrations
471 #members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
471 #members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
472 users_group_to_perm = relationship('UserGroupToPerm', cascade='all')
472 users_group_to_perm = relationship('UserGroupToPerm', cascade='all')
473 users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
473 users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
474 users_group_repo_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
474 users_group_repo_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
475 user_user_group_to_perm = relationship('UserUserGroupToPerm', cascade='all')
475 user_user_group_to_perm = relationship('UserUserGroupToPerm', cascade='all')
476 user_group_user_group_to_perm = relationship('UserGroupUserGroupToPerm ', primaryjoin="UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id", cascade='all')
476 user_group_user_group_to_perm = relationship('UserGroupUserGroupToPerm ', primaryjoin="UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id", cascade='all')
477
477
478 user = relationship('User')
478 user = relationship('User')
479
479
480 def __unicode__(self):
480 def __unicode__(self):
481 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
481 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
482 self.users_group_id,
482 self.users_group_id,
483 self.users_group_name)
483 self.users_group_name)
484
484
485 @classmethod
485 @classmethod
486 def get_by_group_name(cls, group_name, cache=False,
486 def get_by_group_name(cls, group_name, cache=False,
487 case_insensitive=False):
487 case_insensitive=False):
488 if case_insensitive:
488 if case_insensitive:
489 q = cls.query().filter(cls.users_group_name.ilike(group_name))
489 q = cls.query().filter(cls.users_group_name.ilike(group_name))
490 else:
490 else:
491 q = cls.query().filter(cls.users_group_name == group_name)
491 q = cls.query().filter(cls.users_group_name == group_name)
492 if cache:
492 if cache:
493 q = q.options(FromCache(
493 q = q.options(FromCache(
494 "sql_cache_short",
494 "sql_cache_short",
495 "get_user_%s" % _hash_key(group_name)
495 "get_user_%s" % _hash_key(group_name)
496 )
496 )
497 )
497 )
498 return q.scalar()
498 return q.scalar()
499
499
500 @classmethod
500 @classmethod
501 def get(cls, user_group_id, cache=False):
501 def get(cls, user_group_id, cache=False):
502 user_group = cls.query()
502 user_group = cls.query()
503 if cache:
503 if cache:
504 user_group = user_group.options(FromCache("sql_cache_short",
504 user_group = user_group.options(FromCache("sql_cache_short",
505 "get_users_group_%s" % user_group_id))
505 "get_users_group_%s" % user_group_id))
506 return user_group.get(user_group_id)
506 return user_group.get(user_group_id)
507
507
508
508
509 class UserGroupMember(Base, BaseModel):
509 class UserGroupMember(Base, BaseModel):
510 __tablename__ = 'users_groups_members'
510 __tablename__ = 'users_groups_members'
511 __table_args__ = (
511 __table_args__ = (
512 {'extend_existing': True, 'mysql_engine': 'InnoDB',
512 {'extend_existing': True, 'mysql_engine': 'InnoDB',
513 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
513 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
514 )
514 )
515
515
516 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
516 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
517 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
517 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
518 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
518 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
519
519
520 user = relationship('User', lazy='joined')
520 user = relationship('User', lazy='joined')
521 users_group = relationship('UserGroup')
521 users_group = relationship('UserGroup')
522
522
523 def __init__(self, gr_id='', u_id=''):
523 def __init__(self, gr_id='', u_id=''):
524 self.users_group_id = gr_id
524 self.users_group_id = gr_id
525 self.user_id = u_id
525 self.user_id = u_id
526
526
527
527
528 class RepositoryField(Base, BaseModel):
528 class RepositoryField(Base, BaseModel):
529 __tablename__ = 'repositories_fields'
529 __tablename__ = 'repositories_fields'
530 __table_args__ = (
530 __table_args__ = (
531 UniqueConstraint('repository_id', 'field_key'), # no-multi field
531 UniqueConstraint('repository_id', 'field_key'), # no-multi field
532 {'extend_existing': True, 'mysql_engine': 'InnoDB',
532 {'extend_existing': True, 'mysql_engine': 'InnoDB',
533 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
533 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
534 )
534 )
535 PREFIX = 'ex_' # prefix used in form to not conflict with already existing fields
535 PREFIX = 'ex_' # prefix used in form to not conflict with already existing fields
536
536
537 repo_field_id = Column("repo_field_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
537 repo_field_id = Column("repo_field_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
538 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
538 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
539 field_key = Column("field_key", String(250))
539 field_key = Column("field_key", String(250))
540 field_label = Column("field_label", String(1024), nullable=False)
540 field_label = Column("field_label", String(1024), nullable=False)
541 field_value = Column("field_value", String(10000), nullable=False)
541 field_value = Column("field_value", String(10000), nullable=False)
542 field_desc = Column("field_desc", String(1024), nullable=False)
542 field_desc = Column("field_desc", String(1024), nullable=False)
543 field_type = Column("field_type", String(256), nullable=False, unique=None)
543 field_type = Column("field_type", String(256), nullable=False, unique=None)
544 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
544 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
545
545
546 repository = relationship('Repository')
546 repository = relationship('Repository')
547
547
548 @classmethod
548 @classmethod
549 def get_by_key_name(cls, key, repo):
549 def get_by_key_name(cls, key, repo):
550 row = cls.query()\
550 row = cls.query()\
551 .filter(cls.repository == repo)\
551 .filter(cls.repository == repo)\
552 .filter(cls.field_key == key).scalar()
552 .filter(cls.field_key == key).scalar()
553 return row
553 return row
554
554
555
555
556 class Repository(Base, BaseModel):
556 class Repository(Base, BaseModel):
557 __tablename__ = 'repositories'
557 __tablename__ = 'repositories'
558 __table_args__ = (
558 __table_args__ = (
559 UniqueConstraint('repo_name'),
559 UniqueConstraint('repo_name'),
560 Index('r_repo_name_idx', 'repo_name'),
560 Index('r_repo_name_idx', 'repo_name'),
561 {'extend_existing': True, 'mysql_engine': 'InnoDB',
561 {'extend_existing': True, 'mysql_engine': 'InnoDB',
562 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
562 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
563 )
563 )
564
564
565 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
565 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
566 repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None)
566 repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None)
567 clone_uri = Column("clone_uri", String(255), nullable=True, unique=False, default=None)
567 clone_uri = Column("clone_uri", String(255), nullable=True, unique=False, default=None)
568 repo_type = Column("repo_type", String(255), nullable=False, unique=False, default=None)
568 repo_type = Column("repo_type", String(255), nullable=False, unique=False, default=None)
569 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
569 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
570 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
570 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
571 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
571 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
572 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
572 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
573 description = Column("description", String(10000), nullable=True, unique=None, default=None)
573 description = Column("description", String(10000), nullable=True, unique=None, default=None)
574 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
574 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
575 updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
575 updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
576 landing_rev = Column("landing_revision", String(255), nullable=False, unique=False, default=None)
576 landing_rev = Column("landing_revision", String(255), nullable=False, unique=False, default=None)
577 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
577 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
578 _locked = Column("locked", String(255), nullable=True, unique=False, default=None)
578 _locked = Column("locked", String(255), nullable=True, unique=False, default=None)
579 _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) #JSON data
579 _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) #JSON data
580
580
581 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
581 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
582 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
582 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
583
583
584 user = relationship('User')
584 user = relationship('User')
585 fork = relationship('Repository', remote_side=repo_id)
585 fork = relationship('Repository', remote_side=repo_id)
586 group = relationship('RepoGroup')
586 group = relationship('RepoGroup')
587 repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
587 repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
588 users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
588 users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
589 stats = relationship('Statistics', cascade='all', uselist=False)
589 stats = relationship('Statistics', cascade='all', uselist=False)
590
590
591 followers = relationship('UserFollowing',
591 followers = relationship('UserFollowing',
592 primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id',
592 primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id',
593 cascade='all')
593 cascade='all')
594 extra_fields = relationship('RepositoryField',
594 extra_fields = relationship('RepositoryField',
595 cascade="all, delete, delete-orphan")
595 cascade="all, delete, delete-orphan")
596
596
597 logs = relationship('UserLog')
597 logs = relationship('UserLog')
598 comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan")
598 comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan")
599
599
600 pull_requests_org = relationship('PullRequest',
600 pull_requests_org = relationship('PullRequest',
601 primaryjoin='PullRequest.org_repo_id==Repository.repo_id',
601 primaryjoin='PullRequest.org_repo_id==Repository.repo_id',
602 cascade="all, delete, delete-orphan")
602 cascade="all, delete, delete-orphan")
603
603
604 pull_requests_other = relationship('PullRequest',
604 pull_requests_other = relationship('PullRequest',
605 primaryjoin='PullRequest.other_repo_id==Repository.repo_id',
605 primaryjoin='PullRequest.other_repo_id==Repository.repo_id',
606 cascade="all, delete, delete-orphan")
606 cascade="all, delete, delete-orphan")
607
607
608 def __unicode__(self):
608 def __unicode__(self):
609 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id,
609 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id,
610 safe_unicode(self.repo_name))
610 safe_unicode(self.repo_name))
611
611
612 @classmethod
612 @classmethod
613 def get_by_repo_name(cls, repo_name):
613 def get_by_repo_name(cls, repo_name):
614 q = Session().query(cls).filter(cls.repo_name == repo_name)
614 q = Session().query(cls).filter(cls.repo_name == repo_name)
615 q = q.options(joinedload(Repository.fork))\
615 q = q.options(joinedload(Repository.fork))\
616 .options(joinedload(Repository.user))\
616 .options(joinedload(Repository.user))\
617 .options(joinedload(Repository.group))
617 .options(joinedload(Repository.group))
618 return q.scalar()
618 return q.scalar()
619
619
620
620
621 class RepoGroup(Base, BaseModel):
621 class RepoGroup(Base, BaseModel):
622 __tablename__ = 'groups'
622 __tablename__ = 'groups'
623 __table_args__ = (
623 __table_args__ = (
624 UniqueConstraint('group_name', 'group_parent_id'),
624 UniqueConstraint('group_name', 'group_parent_id'),
625 CheckConstraint('group_id != group_parent_id'),
626 {'extend_existing': True, 'mysql_engine': 'InnoDB',
625 {'extend_existing': True, 'mysql_engine': 'InnoDB',
627 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
626 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
628 )
627 )
629 __mapper_args__ = {'order_by': 'group_name'}
628 __mapper_args__ = {'order_by': 'group_name'}
630
629
631 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
630 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
632 group_name = Column("group_name", String(255), nullable=False, unique=True, default=None)
631 group_name = Column("group_name", String(255), nullable=False, unique=True, default=None)
633 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
632 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
634 group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None)
633 group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None)
635 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
634 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
636 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
635 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
637
636
638 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
637 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
639 users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
638 users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
640 parent_group = relationship('RepoGroup', remote_side=group_id)
639 parent_group = relationship('RepoGroup', remote_side=group_id)
641 user = relationship('User')
640 user = relationship('User')
642
641
643 def __init__(self, group_name='', parent_group=None):
642 def __init__(self, group_name='', parent_group=None):
644 self.group_name = group_name
643 self.group_name = group_name
645 self.parent_group = parent_group
644 self.parent_group = parent_group
646
645
647 def __unicode__(self):
646 def __unicode__(self):
648 return u"<%s('id:%s:%s')>" % (self.__class__.__name__, self.group_id,
647 return u"<%s('id:%s:%s')>" % (self.__class__.__name__, self.group_id,
649 self.group_name)
648 self.group_name)
650
649
651 @classmethod
650 @classmethod
652 def url_sep(cls):
651 def url_sep(cls):
653 return URL_SEP
652 return URL_SEP
654
653
655 @classmethod
654 @classmethod
656 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
655 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
657 if case_insensitive:
656 if case_insensitive:
658 gr = cls.query()\
657 gr = cls.query()\
659 .filter(cls.group_name.ilike(group_name))
658 .filter(cls.group_name.ilike(group_name))
660 else:
659 else:
661 gr = cls.query()\
660 gr = cls.query()\
662 .filter(cls.group_name == group_name)
661 .filter(cls.group_name == group_name)
663 if cache:
662 if cache:
664 gr = gr.options(FromCache(
663 gr = gr.options(FromCache(
665 "sql_cache_short",
664 "sql_cache_short",
666 "get_group_%s" % _hash_key(group_name)
665 "get_group_%s" % _hash_key(group_name)
667 )
666 )
668 )
667 )
669 return gr.scalar()
668 return gr.scalar()
670
669
671
670
672 class Permission(Base, BaseModel):
671 class Permission(Base, BaseModel):
673 __tablename__ = 'permissions'
672 __tablename__ = 'permissions'
674 __table_args__ = (
673 __table_args__ = (
675 Index('p_perm_name_idx', 'permission_name'),
674 Index('p_perm_name_idx', 'permission_name'),
676 {'extend_existing': True, 'mysql_engine': 'InnoDB',
675 {'extend_existing': True, 'mysql_engine': 'InnoDB',
677 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
676 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
678 )
677 )
679 PERMS = [
678 PERMS = [
680 ('hg.admin', _('RhodeCode Administrator')),
679 ('hg.admin', _('RhodeCode Administrator')),
681
680
682 ('repository.none', _('Repository no access')),
681 ('repository.none', _('Repository no access')),
683 ('repository.read', _('Repository read access')),
682 ('repository.read', _('Repository read access')),
684 ('repository.write', _('Repository write access')),
683 ('repository.write', _('Repository write access')),
685 ('repository.admin', _('Repository admin access')),
684 ('repository.admin', _('Repository admin access')),
686
685
687 ('group.none', _('Repository group no access')),
686 ('group.none', _('Repository group no access')),
688 ('group.read', _('Repository group read access')),
687 ('group.read', _('Repository group read access')),
689 ('group.write', _('Repository group write access')),
688 ('group.write', _('Repository group write access')),
690 ('group.admin', _('Repository group admin access')),
689 ('group.admin', _('Repository group admin access')),
691
690
692 ('usergroup.none', _('User group no access')),
691 ('usergroup.none', _('User group no access')),
693 ('usergroup.read', _('User group read access')),
692 ('usergroup.read', _('User group read access')),
694 ('usergroup.write', _('User group write access')),
693 ('usergroup.write', _('User group write access')),
695 ('usergroup.admin', _('User group admin access')),
694 ('usergroup.admin', _('User group admin access')),
696
695
697 ('hg.repogroup.create.false', _('Repository Group creation disabled')),
696 ('hg.repogroup.create.false', _('Repository Group creation disabled')),
698 ('hg.repogroup.create.true', _('Repository Group creation enabled')),
697 ('hg.repogroup.create.true', _('Repository Group creation enabled')),
699
698
700 ('hg.usergroup.create.false', _('User Group creation disabled')),
699 ('hg.usergroup.create.false', _('User Group creation disabled')),
701 ('hg.usergroup.create.true', _('User Group creation enabled')),
700 ('hg.usergroup.create.true', _('User Group creation enabled')),
702
701
703 ('hg.create.none', _('Repository creation disabled')),
702 ('hg.create.none', _('Repository creation disabled')),
704 ('hg.create.repository', _('Repository creation enabled')),
703 ('hg.create.repository', _('Repository creation enabled')),
705
704
706 ('hg.fork.none', _('Repository forking disabled')),
705 ('hg.fork.none', _('Repository forking disabled')),
707 ('hg.fork.repository', _('Repository forking enabled')),
706 ('hg.fork.repository', _('Repository forking enabled')),
708
707
709 ('hg.register.none', _('Registration disabled')),
708 ('hg.register.none', _('Registration disabled')),
710 ('hg.register.manual_activate', _('User Registration with manual account activation')),
709 ('hg.register.manual_activate', _('User Registration with manual account activation')),
711 ('hg.register.auto_activate', _('User Registration with automatic account activation')),
710 ('hg.register.auto_activate', _('User Registration with automatic account activation')),
712
711
713 ('hg.extern_activate.manual', _('Manual activation of external account')),
712 ('hg.extern_activate.manual', _('Manual activation of external account')),
714 ('hg.extern_activate.auto', _('Automatic activation of external account')),
713 ('hg.extern_activate.auto', _('Automatic activation of external account')),
715
714
716 ]
715 ]
717
716
718 #definition of system default permissions for DEFAULT user
717 #definition of system default permissions for DEFAULT user
719 DEFAULT_USER_PERMISSIONS = [
718 DEFAULT_USER_PERMISSIONS = [
720 'repository.read',
719 'repository.read',
721 'group.read',
720 'group.read',
722 'usergroup.read',
721 'usergroup.read',
723 'hg.create.repository',
722 'hg.create.repository',
724 'hg.fork.repository',
723 'hg.fork.repository',
725 'hg.register.manual_activate',
724 'hg.register.manual_activate',
726 'hg.extern_activate.auto',
725 'hg.extern_activate.auto',
727 ]
726 ]
728
727
729 # defines which permissions are more important higher the more important
728 # defines which permissions are more important higher the more important
730 # Weight defines which permissions are more important.
729 # Weight defines which permissions are more important.
731 # The higher number the more important.
730 # The higher number the more important.
732 PERM_WEIGHTS = {
731 PERM_WEIGHTS = {
733 'repository.none': 0,
732 'repository.none': 0,
734 'repository.read': 1,
733 'repository.read': 1,
735 'repository.write': 3,
734 'repository.write': 3,
736 'repository.admin': 4,
735 'repository.admin': 4,
737
736
738 'group.none': 0,
737 'group.none': 0,
739 'group.read': 1,
738 'group.read': 1,
740 'group.write': 3,
739 'group.write': 3,
741 'group.admin': 4,
740 'group.admin': 4,
742
741
743 'usergroup.none': 0,
742 'usergroup.none': 0,
744 'usergroup.read': 1,
743 'usergroup.read': 1,
745 'usergroup.write': 3,
744 'usergroup.write': 3,
746 'usergroup.admin': 4,
745 'usergroup.admin': 4,
747 'hg.repogroup.create.false': 0,
746 'hg.repogroup.create.false': 0,
748 'hg.repogroup.create.true': 1,
747 'hg.repogroup.create.true': 1,
749
748
750 'hg.usergroup.create.false': 0,
749 'hg.usergroup.create.false': 0,
751 'hg.usergroup.create.true': 1,
750 'hg.usergroup.create.true': 1,
752
751
753 'hg.fork.none': 0,
752 'hg.fork.none': 0,
754 'hg.fork.repository': 1,
753 'hg.fork.repository': 1,
755 'hg.create.none': 0,
754 'hg.create.none': 0,
756 'hg.create.repository': 1
755 'hg.create.repository': 1
757 }
756 }
758
757
759 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
758 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
760 permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None)
759 permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None)
761 permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None)
760 permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None)
762
761
763 def __unicode__(self):
762 def __unicode__(self):
764 return u"<%s('%s:%s')>" % (
763 return u"<%s('%s:%s')>" % (
765 self.__class__.__name__, self.permission_id, self.permission_name
764 self.__class__.__name__, self.permission_id, self.permission_name
766 )
765 )
767
766
768 @classmethod
767 @classmethod
769 def get_by_key(cls, key):
768 def get_by_key(cls, key):
770 return cls.query().filter(cls.permission_name == key).scalar()
769 return cls.query().filter(cls.permission_name == key).scalar()
771
770
772
771
773 class UserRepoToPerm(Base, BaseModel):
772 class UserRepoToPerm(Base, BaseModel):
774 __tablename__ = 'repo_to_perm'
773 __tablename__ = 'repo_to_perm'
775 __table_args__ = (
774 __table_args__ = (
776 UniqueConstraint('user_id', 'repository_id', 'permission_id'),
775 UniqueConstraint('user_id', 'repository_id', 'permission_id'),
777 {'extend_existing': True, 'mysql_engine': 'InnoDB',
776 {'extend_existing': True, 'mysql_engine': 'InnoDB',
778 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
777 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
779 )
778 )
780 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
779 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
781 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
780 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
782 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
781 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
783 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
782 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
784
783
785 user = relationship('User')
784 user = relationship('User')
786 repository = relationship('Repository')
785 repository = relationship('Repository')
787 permission = relationship('Permission')
786 permission = relationship('Permission')
788
787
789 def __unicode__(self):
788 def __unicode__(self):
790 return u'<%s => %s >' % (self.user, self.repository)
789 return u'<%s => %s >' % (self.user, self.repository)
791
790
792
791
793 class UserUserGroupToPerm(Base, BaseModel):
792 class UserUserGroupToPerm(Base, BaseModel):
794 __tablename__ = 'user_user_group_to_perm'
793 __tablename__ = 'user_user_group_to_perm'
795 __table_args__ = (
794 __table_args__ = (
796 UniqueConstraint('user_id', 'user_group_id', 'permission_id'),
795 UniqueConstraint('user_id', 'user_group_id', 'permission_id'),
797 {'extend_existing': True, 'mysql_engine': 'InnoDB',
796 {'extend_existing': True, 'mysql_engine': 'InnoDB',
798 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
797 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
799 )
798 )
800 user_user_group_to_perm_id = Column("user_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
799 user_user_group_to_perm_id = Column("user_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
801 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
800 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
802 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
801 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
803 user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
802 user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
804
803
805 user = relationship('User')
804 user = relationship('User')
806 user_group = relationship('UserGroup')
805 user_group = relationship('UserGroup')
807 permission = relationship('Permission')
806 permission = relationship('Permission')
808
807
809 def __unicode__(self):
808 def __unicode__(self):
810 return u'<%s => %s >' % (self.user, self.user_group)
809 return u'<%s => %s >' % (self.user, self.user_group)
811
810
812
811
813 class UserToPerm(Base, BaseModel):
812 class UserToPerm(Base, BaseModel):
814 __tablename__ = 'user_to_perm'
813 __tablename__ = 'user_to_perm'
815 __table_args__ = (
814 __table_args__ = (
816 UniqueConstraint('user_id', 'permission_id'),
815 UniqueConstraint('user_id', 'permission_id'),
817 {'extend_existing': True, 'mysql_engine': 'InnoDB',
816 {'extend_existing': True, 'mysql_engine': 'InnoDB',
818 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
817 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
819 )
818 )
820 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
819 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
821 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
820 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
822 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
821 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
823
822
824 user = relationship('User')
823 user = relationship('User')
825 permission = relationship('Permission', lazy='joined')
824 permission = relationship('Permission', lazy='joined')
826
825
827 def __unicode__(self):
826 def __unicode__(self):
828 return u'<%s => %s >' % (self.user, self.permission)
827 return u'<%s => %s >' % (self.user, self.permission)
829
828
830
829
831 class UserGroupRepoToPerm(Base, BaseModel):
830 class UserGroupRepoToPerm(Base, BaseModel):
832 __tablename__ = 'users_group_repo_to_perm'
831 __tablename__ = 'users_group_repo_to_perm'
833 __table_args__ = (
832 __table_args__ = (
834 UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
833 UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
835 {'extend_existing': True, 'mysql_engine': 'InnoDB',
834 {'extend_existing': True, 'mysql_engine': 'InnoDB',
836 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
835 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
837 )
836 )
838 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
837 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
839 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
838 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
840 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
839 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
841 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
840 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
842
841
843 users_group = relationship('UserGroup')
842 users_group = relationship('UserGroup')
844 permission = relationship('Permission')
843 permission = relationship('Permission')
845 repository = relationship('Repository')
844 repository = relationship('Repository')
846
845
847 def __unicode__(self):
846 def __unicode__(self):
848 return u'<UserGroupRepoToPerm:%s => %s >' % (self.users_group, self.repository)
847 return u'<UserGroupRepoToPerm:%s => %s >' % (self.users_group, self.repository)
849
848
850
849
851 class UserGroupUserGroupToPerm(Base, BaseModel):
850 class UserGroupUserGroupToPerm(Base, BaseModel):
852 __tablename__ = 'user_group_user_group_to_perm'
851 __tablename__ = 'user_group_user_group_to_perm'
853 __table_args__ = (
852 __table_args__ = (
854 UniqueConstraint('target_user_group_id', 'user_group_id', 'permission_id'),
853 UniqueConstraint('target_user_group_id', 'user_group_id', 'permission_id'),
855 CheckConstraint('target_user_group_id != user_group_id'),
854 CheckConstraint('target_user_group_id != user_group_id'),
856 {'extend_existing': True, 'mysql_engine': 'InnoDB',
855 {'extend_existing': True, 'mysql_engine': 'InnoDB',
857 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
856 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
858 )
857 )
859 user_group_user_group_to_perm_id = Column("user_group_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
858 user_group_user_group_to_perm_id = Column("user_group_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
860 target_user_group_id = Column("target_user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
859 target_user_group_id = Column("target_user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
861 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
860 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
862 user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
861 user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
863
862
864 target_user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id')
863 target_user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id')
865 user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.user_group_id==UserGroup.users_group_id')
864 user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.user_group_id==UserGroup.users_group_id')
866 permission = relationship('Permission')
865 permission = relationship('Permission')
867
866
868 def __unicode__(self):
867 def __unicode__(self):
869 return u'<UserGroupUserGroup:%s => %s >' % (self.target_user_group, self.user_group)
868 return u'<UserGroupUserGroup:%s => %s >' % (self.target_user_group, self.user_group)
870
869
871
870
872 class UserGroupToPerm(Base, BaseModel):
871 class UserGroupToPerm(Base, BaseModel):
873 __tablename__ = 'users_group_to_perm'
872 __tablename__ = 'users_group_to_perm'
874 __table_args__ = (
873 __table_args__ = (
875 UniqueConstraint('users_group_id', 'permission_id',),
874 UniqueConstraint('users_group_id', 'permission_id',),
876 {'extend_existing': True, 'mysql_engine': 'InnoDB',
875 {'extend_existing': True, 'mysql_engine': 'InnoDB',
877 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
876 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
878 )
877 )
879 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
878 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
880 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
879 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
881 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
880 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
882
881
883 users_group = relationship('UserGroup')
882 users_group = relationship('UserGroup')
884 permission = relationship('Permission')
883 permission = relationship('Permission')
885
884
886
885
887 class UserRepoGroupToPerm(Base, BaseModel):
886 class UserRepoGroupToPerm(Base, BaseModel):
888 __tablename__ = 'user_repo_group_to_perm'
887 __tablename__ = 'user_repo_group_to_perm'
889 __table_args__ = (
888 __table_args__ = (
890 UniqueConstraint('user_id', 'group_id', 'permission_id'),
889 UniqueConstraint('user_id', 'group_id', 'permission_id'),
891 {'extend_existing': True, 'mysql_engine': 'InnoDB',
890 {'extend_existing': True, 'mysql_engine': 'InnoDB',
892 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
891 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
893 )
892 )
894
893
895 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
894 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
896 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
895 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
897 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
896 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
898 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
897 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
899
898
900 user = relationship('User')
899 user = relationship('User')
901 group = relationship('RepoGroup')
900 group = relationship('RepoGroup')
902 permission = relationship('Permission')
901 permission = relationship('Permission')
903
902
904
903
905 class UserGroupRepoGroupToPerm(Base, BaseModel):
904 class UserGroupRepoGroupToPerm(Base, BaseModel):
906 __tablename__ = 'users_group_repo_group_to_perm'
905 __tablename__ = 'users_group_repo_group_to_perm'
907 __table_args__ = (
906 __table_args__ = (
908 UniqueConstraint('users_group_id', 'group_id'),
907 UniqueConstraint('users_group_id', 'group_id'),
909 {'extend_existing': True, 'mysql_engine': 'InnoDB',
908 {'extend_existing': True, 'mysql_engine': 'InnoDB',
910 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
909 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
911 )
910 )
912
911
913 users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
912 users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
914 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
913 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
915 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
914 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
916 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
915 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
917
916
918 users_group = relationship('UserGroup')
917 users_group = relationship('UserGroup')
919 permission = relationship('Permission')
918 permission = relationship('Permission')
920 group = relationship('RepoGroup')
919 group = relationship('RepoGroup')
921
920
922
921
923 class Statistics(Base, BaseModel):
922 class Statistics(Base, BaseModel):
924 __tablename__ = 'statistics'
923 __tablename__ = 'statistics'
925 __table_args__ = (
924 __table_args__ = (
926 UniqueConstraint('repository_id'),
925 UniqueConstraint('repository_id'),
927 {'extend_existing': True, 'mysql_engine': 'InnoDB',
926 {'extend_existing': True, 'mysql_engine': 'InnoDB',
928 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
927 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
929 )
928 )
930 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
929 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
931 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
930 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
932 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
931 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
933 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
932 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
934 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
933 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
935 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
934 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
936
935
937 repository = relationship('Repository', single_parent=True)
936 repository = relationship('Repository', single_parent=True)
938
937
939
938
940 class UserFollowing(Base, BaseModel):
939 class UserFollowing(Base, BaseModel):
941 __tablename__ = 'user_followings'
940 __tablename__ = 'user_followings'
942 __table_args__ = (
941 __table_args__ = (
943 UniqueConstraint('user_id', 'follows_repository_id'),
942 UniqueConstraint('user_id', 'follows_repository_id'),
944 UniqueConstraint('user_id', 'follows_user_id'),
943 UniqueConstraint('user_id', 'follows_user_id'),
945 {'extend_existing': True, 'mysql_engine': 'InnoDB',
944 {'extend_existing': True, 'mysql_engine': 'InnoDB',
946 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
945 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
947 )
946 )
948
947
949 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
948 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
950 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
949 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
951 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
950 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
952 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
951 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
953 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
952 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
954
953
955 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
954 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
956
955
957 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
956 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
958 follows_repository = relationship('Repository', order_by='Repository.repo_name')
957 follows_repository = relationship('Repository', order_by='Repository.repo_name')
959
958
960
959
961 class CacheInvalidation(Base, BaseModel):
960 class CacheInvalidation(Base, BaseModel):
962 __tablename__ = 'cache_invalidation'
961 __tablename__ = 'cache_invalidation'
963 __table_args__ = (
962 __table_args__ = (
964 UniqueConstraint('cache_key'),
963 UniqueConstraint('cache_key'),
965 Index('key_idx', 'cache_key'),
964 Index('key_idx', 'cache_key'),
966 {'extend_existing': True, 'mysql_engine': 'InnoDB',
965 {'extend_existing': True, 'mysql_engine': 'InnoDB',
967 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
966 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
968 )
967 )
969 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
968 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
970 cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None)
969 cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None)
971 cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None)
970 cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None)
972 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
971 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
973
972
974 def __init__(self, cache_key, cache_args=''):
973 def __init__(self, cache_key, cache_args=''):
975 self.cache_key = cache_key
974 self.cache_key = cache_key
976 self.cache_args = cache_args
975 self.cache_args = cache_args
977 self.cache_active = False
976 self.cache_active = False
978
977
979
978
980 class ChangesetComment(Base, BaseModel):
979 class ChangesetComment(Base, BaseModel):
981 __tablename__ = 'changeset_comments'
980 __tablename__ = 'changeset_comments'
982 __table_args__ = (
981 __table_args__ = (
983 Index('cc_revision_idx', 'revision'),
982 Index('cc_revision_idx', 'revision'),
984 {'extend_existing': True, 'mysql_engine': 'InnoDB',
983 {'extend_existing': True, 'mysql_engine': 'InnoDB',
985 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
984 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
986 )
985 )
987 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
986 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
988 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
987 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
989 revision = Column('revision', String(40), nullable=True)
988 revision = Column('revision', String(40), nullable=True)
990 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
989 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
991 line_no = Column('line_no', Unicode(10), nullable=True)
990 line_no = Column('line_no', Unicode(10), nullable=True)
992 hl_lines = Column('hl_lines', Unicode(512), nullable=True)
991 hl_lines = Column('hl_lines', Unicode(512), nullable=True)
993 f_path = Column('f_path', Unicode(1000), nullable=True)
992 f_path = Column('f_path', Unicode(1000), nullable=True)
994 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
993 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
995 text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False)
994 text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False)
996 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
995 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
997 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
996 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
998
997
999 author = relationship('User', lazy='joined')
998 author = relationship('User', lazy='joined')
1000 repo = relationship('Repository')
999 repo = relationship('Repository')
1001 status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan")
1000 status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan")
1002 pull_request = relationship('PullRequest', lazy='joined')
1001 pull_request = relationship('PullRequest', lazy='joined')
1003
1002
1004
1003
1005 class ChangesetStatus(Base, BaseModel):
1004 class ChangesetStatus(Base, BaseModel):
1006 __tablename__ = 'changeset_statuses'
1005 __tablename__ = 'changeset_statuses'
1007 __table_args__ = (
1006 __table_args__ = (
1008 Index('cs_revision_idx', 'revision'),
1007 Index('cs_revision_idx', 'revision'),
1009 Index('cs_version_idx', 'version'),
1008 Index('cs_version_idx', 'version'),
1010 UniqueConstraint('repo_id', 'revision', 'version'),
1009 UniqueConstraint('repo_id', 'revision', 'version'),
1011 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1010 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1012 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1011 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1013 )
1012 )
1014 STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed'
1013 STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed'
1015 STATUS_APPROVED = 'approved'
1014 STATUS_APPROVED = 'approved'
1016 STATUS_REJECTED = 'rejected'
1015 STATUS_REJECTED = 'rejected'
1017 STATUS_UNDER_REVIEW = 'under_review'
1016 STATUS_UNDER_REVIEW = 'under_review'
1018
1017
1019 STATUSES = [
1018 STATUSES = [
1020 (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default
1019 (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default
1021 (STATUS_APPROVED, _("Approved")),
1020 (STATUS_APPROVED, _("Approved")),
1022 (STATUS_REJECTED, _("Rejected")),
1021 (STATUS_REJECTED, _("Rejected")),
1023 (STATUS_UNDER_REVIEW, _("Under Review")),
1022 (STATUS_UNDER_REVIEW, _("Under Review")),
1024 ]
1023 ]
1025
1024
1026 changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True)
1025 changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True)
1027 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1026 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1028 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1027 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1029 revision = Column('revision', String(40), nullable=False)
1028 revision = Column('revision', String(40), nullable=False)
1030 status = Column('status', String(128), nullable=False, default=DEFAULT)
1029 status = Column('status', String(128), nullable=False, default=DEFAULT)
1031 changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id'))
1030 changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id'))
1032 modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
1031 modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
1033 version = Column('version', Integer(), nullable=False, default=0)
1032 version = Column('version', Integer(), nullable=False, default=0)
1034 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
1033 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
1035
1034
1036 author = relationship('User', lazy='joined')
1035 author = relationship('User', lazy='joined')
1037 repo = relationship('Repository')
1036 repo = relationship('Repository')
1038 comment = relationship('ChangesetComment', lazy='joined')
1037 comment = relationship('ChangesetComment', lazy='joined')
1039 pull_request = relationship('PullRequest', lazy='joined')
1038 pull_request = relationship('PullRequest', lazy='joined')
1040
1039
1041
1040
1042
1041
1043 class PullRequest(Base, BaseModel):
1042 class PullRequest(Base, BaseModel):
1044 __tablename__ = 'pull_requests'
1043 __tablename__ = 'pull_requests'
1045 __table_args__ = (
1044 __table_args__ = (
1046 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1045 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1047 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1046 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1048 )
1047 )
1049
1048
1050 STATUS_NEW = u'new'
1049 STATUS_NEW = u'new'
1051 STATUS_OPEN = u'open'
1050 STATUS_OPEN = u'open'
1052 STATUS_CLOSED = u'closed'
1051 STATUS_CLOSED = u'closed'
1053
1052
1054 pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True)
1053 pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True)
1055 title = Column('title', Unicode(256), nullable=True)
1054 title = Column('title', Unicode(256), nullable=True)
1056 description = Column('description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), nullable=True)
1055 description = Column('description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), nullable=True)
1057 status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW)
1056 status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW)
1058 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1057 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1059 updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1058 updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1060 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1059 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1061 _revisions = Column('revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql'))
1060 _revisions = Column('revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql'))
1062 org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1061 org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1063 org_ref = Column('org_ref', Unicode(256), nullable=False)
1062 org_ref = Column('org_ref', Unicode(256), nullable=False)
1064 other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1063 other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1065 other_ref = Column('other_ref', Unicode(256), nullable=False)
1064 other_ref = Column('other_ref', Unicode(256), nullable=False)
1066
1065
1067 author = relationship('User', lazy='joined')
1066 author = relationship('User', lazy='joined')
1068 reviewers = relationship('PullRequestReviewers',
1067 reviewers = relationship('PullRequestReviewers',
1069 cascade="all, delete, delete-orphan")
1068 cascade="all, delete, delete-orphan")
1070 org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id')
1069 org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id')
1071 other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id')
1070 other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id')
1072 statuses = relationship('ChangesetStatus')
1071 statuses = relationship('ChangesetStatus')
1073 comments = relationship('ChangesetComment',
1072 comments = relationship('ChangesetComment',
1074 cascade="all, delete, delete-orphan")
1073 cascade="all, delete, delete-orphan")
1075
1074
1076
1075
1077 class PullRequestReviewers(Base, BaseModel):
1076 class PullRequestReviewers(Base, BaseModel):
1078 __tablename__ = 'pull_request_reviewers'
1077 __tablename__ = 'pull_request_reviewers'
1079 __table_args__ = (
1078 __table_args__ = (
1080 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1079 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1081 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1080 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1082 )
1081 )
1083
1082
1084 def __init__(self, user=None, pull_request=None):
1083 def __init__(self, user=None, pull_request=None):
1085 self.user = user
1084 self.user = user
1086 self.pull_request = pull_request
1085 self.pull_request = pull_request
1087
1086
1088 pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True)
1087 pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True)
1089 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False)
1088 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False)
1090 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True)
1089 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True)
1091
1090
1092 user = relationship('User')
1091 user = relationship('User')
1093 pull_request = relationship('PullRequest')
1092 pull_request = relationship('PullRequest')
1094
1093
1095
1094
1096 class Notification(Base, BaseModel):
1095 class Notification(Base, BaseModel):
1097 __tablename__ = 'notifications'
1096 __tablename__ = 'notifications'
1098 __table_args__ = (
1097 __table_args__ = (
1099 Index('notification_type_idx', 'type'),
1098 Index('notification_type_idx', 'type'),
1100 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1099 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1101 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1100 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1102 )
1101 )
1103
1102
1104 TYPE_CHANGESET_COMMENT = u'cs_comment'
1103 TYPE_CHANGESET_COMMENT = u'cs_comment'
1105 TYPE_MESSAGE = u'message'
1104 TYPE_MESSAGE = u'message'
1106 TYPE_MENTION = u'mention'
1105 TYPE_MENTION = u'mention'
1107 TYPE_REGISTRATION = u'registration'
1106 TYPE_REGISTRATION = u'registration'
1108 TYPE_PULL_REQUEST = u'pull_request'
1107 TYPE_PULL_REQUEST = u'pull_request'
1109 TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment'
1108 TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment'
1110
1109
1111 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
1110 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
1112 subject = Column('subject', Unicode(512), nullable=True)
1111 subject = Column('subject', Unicode(512), nullable=True)
1113 body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True)
1112 body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True)
1114 created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
1113 created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
1115 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1114 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1116 type_ = Column('type', Unicode(256))
1115 type_ = Column('type', Unicode(256))
1117
1116
1118 created_by_user = relationship('User')
1117 created_by_user = relationship('User')
1119 notifications_to_users = relationship('UserNotification', lazy='joined',
1118 notifications_to_users = relationship('UserNotification', lazy='joined',
1120 cascade="all, delete, delete-orphan")
1119 cascade="all, delete, delete-orphan")
1121
1120
1122
1121
1123 class UserNotification(Base, BaseModel):
1122 class UserNotification(Base, BaseModel):
1124 __tablename__ = 'user_to_notification'
1123 __tablename__ = 'user_to_notification'
1125 __table_args__ = (
1124 __table_args__ = (
1126 UniqueConstraint('user_id', 'notification_id'),
1125 UniqueConstraint('user_id', 'notification_id'),
1127 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1126 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1128 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1127 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1129 )
1128 )
1130 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
1129 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
1131 notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
1130 notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
1132 read = Column('read', Boolean, default=False)
1131 read = Column('read', Boolean, default=False)
1133 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
1132 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
1134
1133
1135 user = relationship('User', lazy="joined")
1134 user = relationship('User', lazy="joined")
1136 notification = relationship('Notification', lazy="joined",
1135 notification = relationship('Notification', lazy="joined",
1137 order_by=lambda: Notification.created_on.desc(),)
1136 order_by=lambda: Notification.created_on.desc(),)
1138
1137
1139
1138
1140 class Gist(Base, BaseModel):
1139 class Gist(Base, BaseModel):
1141 __tablename__ = 'gists'
1140 __tablename__ = 'gists'
1142 __table_args__ = (
1141 __table_args__ = (
1143 Index('g_gist_access_id_idx', 'gist_access_id'),
1142 Index('g_gist_access_id_idx', 'gist_access_id'),
1144 Index('g_created_on_idx', 'created_on'),
1143 Index('g_created_on_idx', 'created_on'),
1145 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1144 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1146 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1145 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1147 )
1146 )
1148 GIST_PUBLIC = u'public'
1147 GIST_PUBLIC = u'public'
1149 GIST_PRIVATE = u'private'
1148 GIST_PRIVATE = u'private'
1150
1149
1151 gist_id = Column('gist_id', Integer(), primary_key=True)
1150 gist_id = Column('gist_id', Integer(), primary_key=True)
1152 gist_access_id = Column('gist_access_id', Unicode(250))
1151 gist_access_id = Column('gist_access_id', Unicode(250))
1153 gist_description = Column('gist_description', UnicodeText().with_variant(UnicodeText(1024), 'mysql'))
1152 gist_description = Column('gist_description', UnicodeText().with_variant(UnicodeText(1024), 'mysql'))
1154 gist_owner = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=True)
1153 gist_owner = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=True)
1155 gist_expires = Column('gist_expires', Float(53), nullable=False)
1154 gist_expires = Column('gist_expires', Float(53), nullable=False)
1156 gist_type = Column('gist_type', Unicode(128), nullable=False)
1155 gist_type = Column('gist_type', Unicode(128), nullable=False)
1157 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1156 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1158 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1157 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1159
1158
1160 owner = relationship('User')
1159 owner = relationship('User')
1161
1160
1162
1161
1163 class DbMigrateVersion(Base, BaseModel):
1162 class DbMigrateVersion(Base, BaseModel):
1164 __tablename__ = 'db_migrate_version'
1163 __tablename__ = 'db_migrate_version'
1165 __table_args__ = (
1164 __table_args__ = (
1166 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1165 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1167 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1166 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1168 )
1167 )
1169 repository_id = Column('repository_id', String(250), primary_key=True)
1168 repository_id = Column('repository_id', String(250), primary_key=True)
1170 repository_path = Column('repository_path', Text)
1169 repository_path = Column('repository_path', Text)
1171 version = Column('version', Integer)
1170 version = Column('version', Integer)
@@ -1,1172 +1,1171 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2019 RhodeCode GmbH
3 # Copyright (C) 2010-2019 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import os
21 import os
22 import time
22 import time
23 import logging
23 import logging
24 import datetime
24 import datetime
25 import traceback
25 import traceback
26 import hashlib
26 import hashlib
27 import collections
27 import collections
28 import functools
28 import functools
29
29
30 from sqlalchemy import *
30 from sqlalchemy import *
31 from sqlalchemy.ext.hybrid import hybrid_property
31 from sqlalchemy.ext.hybrid import hybrid_property
32 from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
32 from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
33 from sqlalchemy.exc import DatabaseError
33 from sqlalchemy.exc import DatabaseError
34 from beaker.cache import cache_region, region_invalidate
34 from beaker.cache import cache_region, region_invalidate
35 from webob.exc import HTTPNotFound
35 from webob.exc import HTTPNotFound
36
36
37 from rhodecode.translation import _
37 from rhodecode.translation import _
38
38
39 from rhodecode.lib.vcs import get_backend
39 from rhodecode.lib.vcs import get_backend
40 from rhodecode.lib.vcs.utils.helpers import get_scm
40 from rhodecode.lib.vcs.utils.helpers import get_scm
41 from rhodecode.lib.vcs.exceptions import VCSError
41 from rhodecode.lib.vcs.exceptions import VCSError
42 from zope.cachedescriptors.property import Lazy as LazyProperty
42 from zope.cachedescriptors.property import Lazy as LazyProperty
43 from rhodecode.lib.vcs.backends.base import EmptyCommit
43 from rhodecode.lib.vcs.backends.base import EmptyCommit
44
44
45 from rhodecode.lib.utils2 import str2bool, safe_str, get_commit_safe, \
45 from rhodecode.lib.utils2 import str2bool, safe_str, get_commit_safe, \
46 safe_unicode, remove_prefix, time_to_datetime, aslist, Optional, safe_int
46 safe_unicode, remove_prefix, time_to_datetime, aslist, Optional, safe_int
47 from rhodecode.lib.ext_json import json
47 from rhodecode.lib.ext_json import json
48 from rhodecode.lib.caching_query import FromCache
48 from rhodecode.lib.caching_query import FromCache
49
49
50 from rhodecode.model.meta import Base, Session
50 from rhodecode.model.meta import Base, Session
51
51
52 URL_SEP = '/'
52 URL_SEP = '/'
53 log = logging.getLogger(__name__)
53 log = logging.getLogger(__name__)
54
54
55 #==============================================================================
55 #==============================================================================
56 # BASE CLASSES
56 # BASE CLASSES
57 #==============================================================================
57 #==============================================================================
58
58
59 _hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest()
59 _hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest()
60
60
61
61
62 class BaseModel(object):
62 class BaseModel(object):
63 """
63 """
64 Base Model for all classes
64 Base Model for all classes
65 """
65 """
66
66
67 @classmethod
67 @classmethod
68 def _get_keys(cls):
68 def _get_keys(cls):
69 """return column names for this model """
69 """return column names for this model """
70 return class_mapper(cls).c.keys()
70 return class_mapper(cls).c.keys()
71
71
72 def get_dict(self):
72 def get_dict(self):
73 """
73 """
74 return dict with keys and values corresponding
74 return dict with keys and values corresponding
75 to this model data """
75 to this model data """
76
76
77 d = {}
77 d = {}
78 for k in self._get_keys():
78 for k in self._get_keys():
79 d[k] = getattr(self, k)
79 d[k] = getattr(self, k)
80
80
81 # also use __json__() if present to get additional fields
81 # also use __json__() if present to get additional fields
82 _json_attr = getattr(self, '__json__', None)
82 _json_attr = getattr(self, '__json__', None)
83 if _json_attr:
83 if _json_attr:
84 # update with attributes from __json__
84 # update with attributes from __json__
85 if callable(_json_attr):
85 if callable(_json_attr):
86 _json_attr = _json_attr()
86 _json_attr = _json_attr()
87 for k, val in _json_attr.iteritems():
87 for k, val in _json_attr.iteritems():
88 d[k] = val
88 d[k] = val
89 return d
89 return d
90
90
91 def get_appstruct(self):
91 def get_appstruct(self):
92 """return list with keys and values tupples corresponding
92 """return list with keys and values tupples corresponding
93 to this model data """
93 to this model data """
94
94
95 l = []
95 l = []
96 for k in self._get_keys():
96 for k in self._get_keys():
97 l.append((k, getattr(self, k),))
97 l.append((k, getattr(self, k),))
98 return l
98 return l
99
99
100 def populate_obj(self, populate_dict):
100 def populate_obj(self, populate_dict):
101 """populate model with data from given populate_dict"""
101 """populate model with data from given populate_dict"""
102
102
103 for k in self._get_keys():
103 for k in self._get_keys():
104 if k in populate_dict:
104 if k in populate_dict:
105 setattr(self, k, populate_dict[k])
105 setattr(self, k, populate_dict[k])
106
106
107 @classmethod
107 @classmethod
108 def query(cls):
108 def query(cls):
109 return Session().query(cls)
109 return Session().query(cls)
110
110
111 @classmethod
111 @classmethod
112 def get(cls, id_):
112 def get(cls, id_):
113 if id_:
113 if id_:
114 return cls.query().get(id_)
114 return cls.query().get(id_)
115
115
116 @classmethod
116 @classmethod
117 def get_or_404(cls, id_):
117 def get_or_404(cls, id_):
118 try:
118 try:
119 id_ = int(id_)
119 id_ = int(id_)
120 except (TypeError, ValueError):
120 except (TypeError, ValueError):
121 raise HTTPNotFound
121 raise HTTPNotFound
122
122
123 res = cls.query().get(id_)
123 res = cls.query().get(id_)
124 if not res:
124 if not res:
125 raise HTTPNotFound
125 raise HTTPNotFound
126 return res
126 return res
127
127
128 @classmethod
128 @classmethod
129 def getAll(cls):
129 def getAll(cls):
130 # deprecated and left for backward compatibility
130 # deprecated and left for backward compatibility
131 return cls.get_all()
131 return cls.get_all()
132
132
133 @classmethod
133 @classmethod
134 def get_all(cls):
134 def get_all(cls):
135 return cls.query().all()
135 return cls.query().all()
136
136
137 @classmethod
137 @classmethod
138 def delete(cls, id_):
138 def delete(cls, id_):
139 obj = cls.query().get(id_)
139 obj = cls.query().get(id_)
140 Session().delete(obj)
140 Session().delete(obj)
141
141
142 def __repr__(self):
142 def __repr__(self):
143 if hasattr(self, '__unicode__'):
143 if hasattr(self, '__unicode__'):
144 # python repr needs to return str
144 # python repr needs to return str
145 try:
145 try:
146 return safe_str(self.__unicode__())
146 return safe_str(self.__unicode__())
147 except UnicodeDecodeError:
147 except UnicodeDecodeError:
148 pass
148 pass
149 return '<DB:%s>' % (self.__class__.__name__)
149 return '<DB:%s>' % (self.__class__.__name__)
150
150
151
151
152 class RhodeCodeSetting(Base, BaseModel):
152 class RhodeCodeSetting(Base, BaseModel):
153 SETTINGS_TYPES = {
153 SETTINGS_TYPES = {
154 'str': safe_str,
154 'str': safe_str,
155 'int': safe_int,
155 'int': safe_int,
156 'unicode': safe_unicode,
156 'unicode': safe_unicode,
157 'bool': str2bool,
157 'bool': str2bool,
158 'list': functools.partial(aslist, sep=',')
158 'list': functools.partial(aslist, sep=',')
159 }
159 }
160 __tablename__ = 'rhodecode_settings'
160 __tablename__ = 'rhodecode_settings'
161 __table_args__ = (
161 __table_args__ = (
162 UniqueConstraint('app_settings_name'),
162 UniqueConstraint('app_settings_name'),
163 {'extend_existing': True, 'mysql_engine': 'InnoDB',
163 {'extend_existing': True, 'mysql_engine': 'InnoDB',
164 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
164 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
165 )
165 )
166 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
166 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
167 app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None)
167 app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None)
168 _app_settings_value = Column("app_settings_value", String(4096), nullable=True, unique=None, default=None)
168 _app_settings_value = Column("app_settings_value", String(4096), nullable=True, unique=None, default=None)
169 _app_settings_type = Column("app_settings_type", String(255), nullable=True, unique=None, default=None)
169 _app_settings_type = Column("app_settings_type", String(255), nullable=True, unique=None, default=None)
170
170
171 def __init__(self, key='', val='', type='unicode'):
171 def __init__(self, key='', val='', type='unicode'):
172 self.app_settings_name = key
172 self.app_settings_name = key
173 self.app_settings_value = val
173 self.app_settings_value = val
174 self.app_settings_type = type
174 self.app_settings_type = type
175
175
176 @validates('_app_settings_value')
176 @validates('_app_settings_value')
177 def validate_settings_value(self, key, val):
177 def validate_settings_value(self, key, val):
178 assert type(val) == unicode
178 assert type(val) == unicode
179 return val
179 return val
180
180
181 @hybrid_property
181 @hybrid_property
182 def app_settings_value(self):
182 def app_settings_value(self):
183 v = self._app_settings_value
183 v = self._app_settings_value
184 _type = self.app_settings_type
184 _type = self.app_settings_type
185 converter = self.SETTINGS_TYPES.get(_type) or self.SETTINGS_TYPES['unicode']
185 converter = self.SETTINGS_TYPES.get(_type) or self.SETTINGS_TYPES['unicode']
186 return converter(v)
186 return converter(v)
187
187
188 @app_settings_value.setter
188 @app_settings_value.setter
189 def app_settings_value(self, val):
189 def app_settings_value(self, val):
190 """
190 """
191 Setter that will always make sure we use unicode in app_settings_value
191 Setter that will always make sure we use unicode in app_settings_value
192
192
193 :param val:
193 :param val:
194 """
194 """
195 self._app_settings_value = safe_unicode(val)
195 self._app_settings_value = safe_unicode(val)
196
196
197 @hybrid_property
197 @hybrid_property
198 def app_settings_type(self):
198 def app_settings_type(self):
199 return self._app_settings_type
199 return self._app_settings_type
200
200
201 @app_settings_type.setter
201 @app_settings_type.setter
202 def app_settings_type(self, val):
202 def app_settings_type(self, val):
203 if val not in self.SETTINGS_TYPES:
203 if val not in self.SETTINGS_TYPES:
204 raise Exception('type must be one of %s got %s'
204 raise Exception('type must be one of %s got %s'
205 % (self.SETTINGS_TYPES.keys(), val))
205 % (self.SETTINGS_TYPES.keys(), val))
206 self._app_settings_type = val
206 self._app_settings_type = val
207
207
208 def __unicode__(self):
208 def __unicode__(self):
209 return u"<%s('%s:%s[%s]')>" % (
209 return u"<%s('%s:%s[%s]')>" % (
210 self.__class__.__name__,
210 self.__class__.__name__,
211 self.app_settings_name, self.app_settings_value, self.app_settings_type
211 self.app_settings_name, self.app_settings_value, self.app_settings_type
212 )
212 )
213
213
214
214
215 class RhodeCodeUi(Base, BaseModel):
215 class RhodeCodeUi(Base, BaseModel):
216 __tablename__ = 'rhodecode_ui'
216 __tablename__ = 'rhodecode_ui'
217 __table_args__ = (
217 __table_args__ = (
218 UniqueConstraint('ui_key'),
218 UniqueConstraint('ui_key'),
219 {'extend_existing': True, 'mysql_engine': 'InnoDB',
219 {'extend_existing': True, 'mysql_engine': 'InnoDB',
220 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
220 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
221 )
221 )
222
222
223 HOOK_REPO_SIZE = 'changegroup.repo_size'
223 HOOK_REPO_SIZE = 'changegroup.repo_size'
224 HOOK_PUSH = 'changegroup.push_logger'
224 HOOK_PUSH = 'changegroup.push_logger'
225 HOOK_PRE_PUSH = 'prechangegroup.pre_push'
225 HOOK_PRE_PUSH = 'prechangegroup.pre_push'
226 HOOK_PULL = 'outgoing.pull_logger'
226 HOOK_PULL = 'outgoing.pull_logger'
227 HOOK_PRE_PULL = 'preoutgoing.pre_pull'
227 HOOK_PRE_PULL = 'preoutgoing.pre_pull'
228
228
229 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
229 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
230 ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None)
230 ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None)
231 ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None)
231 ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None)
232 ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None)
232 ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None)
233 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
233 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
234
234
235
235
236
236
237 class User(Base, BaseModel):
237 class User(Base, BaseModel):
238 __tablename__ = 'users'
238 __tablename__ = 'users'
239 __table_args__ = (
239 __table_args__ = (
240 UniqueConstraint('username'), UniqueConstraint('email'),
240 UniqueConstraint('username'), UniqueConstraint('email'),
241 Index('u_username_idx', 'username'),
241 Index('u_username_idx', 'username'),
242 Index('u_email_idx', 'email'),
242 Index('u_email_idx', 'email'),
243 {'extend_existing': True, 'mysql_engine': 'InnoDB',
243 {'extend_existing': True, 'mysql_engine': 'InnoDB',
244 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
244 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
245 )
245 )
246 DEFAULT_USER = 'default'
246 DEFAULT_USER = 'default'
247
247
248 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
248 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
249 username = Column("username", String(255), nullable=True, unique=None, default=None)
249 username = Column("username", String(255), nullable=True, unique=None, default=None)
250 password = Column("password", String(255), nullable=True, unique=None, default=None)
250 password = Column("password", String(255), nullable=True, unique=None, default=None)
251 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
251 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
252 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
252 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
253 name = Column("firstname", String(255), nullable=True, unique=None, default=None)
253 name = Column("firstname", String(255), nullable=True, unique=None, default=None)
254 lastname = Column("lastname", String(255), nullable=True, unique=None, default=None)
254 lastname = Column("lastname", String(255), nullable=True, unique=None, default=None)
255 _email = Column("email", String(255), nullable=True, unique=None, default=None)
255 _email = Column("email", String(255), nullable=True, unique=None, default=None)
256 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
256 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
257 extern_type = Column("extern_type", String(255), nullable=True, unique=None, default=None)
257 extern_type = Column("extern_type", String(255), nullable=True, unique=None, default=None)
258 extern_name = Column("extern_name", String(255), nullable=True, unique=None, default=None)
258 extern_name = Column("extern_name", String(255), nullable=True, unique=None, default=None)
259 api_key = Column("api_key", String(255), nullable=True, unique=None, default=None)
259 api_key = Column("api_key", String(255), nullable=True, unique=None, default=None)
260 inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
260 inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
261 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
261 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
262
262
263 user_log = relationship('UserLog')
263 user_log = relationship('UserLog')
264 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
264 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
265
265
266 repositories = relationship('Repository')
266 repositories = relationship('Repository')
267 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
267 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
268 followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all')
268 followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all')
269
269
270 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
270 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
271 repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all')
271 repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all')
272
272
273 group_member = relationship('UserGroupMember', cascade='all')
273 group_member = relationship('UserGroupMember', cascade='all')
274
274
275 notifications = relationship('UserNotification', cascade='all')
275 notifications = relationship('UserNotification', cascade='all')
276 # notifications assigned to this user
276 # notifications assigned to this user
277 user_created_notifications = relationship('Notification', cascade='all')
277 user_created_notifications = relationship('Notification', cascade='all')
278 # comments created by this user
278 # comments created by this user
279 user_comments = relationship('ChangesetComment', cascade='all')
279 user_comments = relationship('ChangesetComment', cascade='all')
280 user_emails = relationship('UserEmailMap', cascade='all')
280 user_emails = relationship('UserEmailMap', cascade='all')
281
281
282 @hybrid_property
282 @hybrid_property
283 def email(self):
283 def email(self):
284 return self._email
284 return self._email
285
285
286 @email.setter
286 @email.setter
287 def email(self, val):
287 def email(self, val):
288 self._email = val.lower() if val else None
288 self._email = val.lower() if val else None
289
289
290 @property
290 @property
291 def firstname(self):
291 def firstname(self):
292 # alias for future
292 # alias for future
293 return self.name
293 return self.name
294
294
295 @property
295 @property
296 def username_and_name(self):
296 def username_and_name(self):
297 return '%s (%s %s)' % (self.username, self.firstname, self.lastname)
297 return '%s (%s %s)' % (self.username, self.firstname, self.lastname)
298
298
299 @property
299 @property
300 def full_name(self):
300 def full_name(self):
301 return '%s %s' % (self.firstname, self.lastname)
301 return '%s %s' % (self.firstname, self.lastname)
302
302
303 @property
303 @property
304 def full_contact(self):
304 def full_contact(self):
305 return '%s %s <%s>' % (self.firstname, self.lastname, self.email)
305 return '%s %s <%s>' % (self.firstname, self.lastname, self.email)
306
306
307 @property
307 @property
308 def short_contact(self):
308 def short_contact(self):
309 return '%s %s' % (self.firstname, self.lastname)
309 return '%s %s' % (self.firstname, self.lastname)
310
310
311 @property
311 @property
312 def is_admin(self):
312 def is_admin(self):
313 return self.admin
313 return self.admin
314
314
315 @classmethod
315 @classmethod
316 def get_by_username(cls, username, case_insensitive=False, cache=False):
316 def get_by_username(cls, username, case_insensitive=False, cache=False):
317 if case_insensitive:
317 if case_insensitive:
318 q = cls.query().filter(cls.username.ilike(username))
318 q = cls.query().filter(cls.username.ilike(username))
319 else:
319 else:
320 q = cls.query().filter(cls.username == username)
320 q = cls.query().filter(cls.username == username)
321
321
322 if cache:
322 if cache:
323 q = q.options(FromCache(
323 q = q.options(FromCache(
324 "sql_cache_short",
324 "sql_cache_short",
325 "get_user_%s" % _hash_key(username)
325 "get_user_%s" % _hash_key(username)
326 )
326 )
327 )
327 )
328 return q.scalar()
328 return q.scalar()
329
329
330 @classmethod
330 @classmethod
331 def get_by_auth_token(cls, auth_token, cache=False):
331 def get_by_auth_token(cls, auth_token, cache=False):
332 q = cls.query().filter(cls.api_key == auth_token)
332 q = cls.query().filter(cls.api_key == auth_token)
333
333
334 if cache:
334 if cache:
335 q = q.options(FromCache("sql_cache_short",
335 q = q.options(FromCache("sql_cache_short",
336 "get_auth_token_%s" % auth_token))
336 "get_auth_token_%s" % auth_token))
337 return q.scalar()
337 return q.scalar()
338
338
339 @classmethod
339 @classmethod
340 def get_by_email(cls, email, case_insensitive=False, cache=False):
340 def get_by_email(cls, email, case_insensitive=False, cache=False):
341 if case_insensitive:
341 if case_insensitive:
342 q = cls.query().filter(cls.email.ilike(email))
342 q = cls.query().filter(cls.email.ilike(email))
343 else:
343 else:
344 q = cls.query().filter(cls.email == email)
344 q = cls.query().filter(cls.email == email)
345
345
346 if cache:
346 if cache:
347 q = q.options(FromCache("sql_cache_short",
347 q = q.options(FromCache("sql_cache_short",
348 "get_email_key_%s" % email))
348 "get_email_key_%s" % email))
349
349
350 ret = q.scalar()
350 ret = q.scalar()
351 if ret is None:
351 if ret is None:
352 q = UserEmailMap.query()
352 q = UserEmailMap.query()
353 # try fetching in alternate email map
353 # try fetching in alternate email map
354 if case_insensitive:
354 if case_insensitive:
355 q = q.filter(UserEmailMap.email.ilike(email))
355 q = q.filter(UserEmailMap.email.ilike(email))
356 else:
356 else:
357 q = q.filter(UserEmailMap.email == email)
357 q = q.filter(UserEmailMap.email == email)
358 q = q.options(joinedload(UserEmailMap.user))
358 q = q.options(joinedload(UserEmailMap.user))
359 if cache:
359 if cache:
360 q = q.options(FromCache("sql_cache_short",
360 q = q.options(FromCache("sql_cache_short",
361 "get_email_map_key_%s" % email))
361 "get_email_map_key_%s" % email))
362 ret = getattr(q.scalar(), 'user', None)
362 ret = getattr(q.scalar(), 'user', None)
363
363
364 return ret
364 return ret
365
365
366 @classmethod
366 @classmethod
367 def get_first_admin(cls):
367 def get_first_admin(cls):
368 user = User.query().filter(User.admin == True).first()
368 user = User.query().filter(User.admin == True).first()
369 if user is None:
369 if user is None:
370 raise Exception('Missing administrative account!')
370 raise Exception('Missing administrative account!')
371 return user
371 return user
372
372
373 @classmethod
373 @classmethod
374 def get_default_user(cls, cache=False):
374 def get_default_user(cls, cache=False):
375 user = User.get_by_username(User.DEFAULT_USER, cache=cache)
375 user = User.get_by_username(User.DEFAULT_USER, cache=cache)
376 if user is None:
376 if user is None:
377 raise Exception('Missing default account!')
377 raise Exception('Missing default account!')
378 return user
378 return user
379
379
380
380
381
381
382
382
383 class UserEmailMap(Base, BaseModel):
383 class UserEmailMap(Base, BaseModel):
384 __tablename__ = 'user_email_map'
384 __tablename__ = 'user_email_map'
385 __table_args__ = (
385 __table_args__ = (
386 Index('uem_email_idx', 'email'),
386 Index('uem_email_idx', 'email'),
387 UniqueConstraint('email'),
387 UniqueConstraint('email'),
388 {'extend_existing': True, 'mysql_engine': 'InnoDB',
388 {'extend_existing': True, 'mysql_engine': 'InnoDB',
389 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
389 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
390 )
390 )
391 __mapper_args__ = {}
391 __mapper_args__ = {}
392
392
393 email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
393 email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
394 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
394 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
395 _email = Column("email", String(255), nullable=True, unique=False, default=None)
395 _email = Column("email", String(255), nullable=True, unique=False, default=None)
396 user = relationship('User', lazy='joined')
396 user = relationship('User', lazy='joined')
397
397
398 @validates('_email')
398 @validates('_email')
399 def validate_email(self, key, email):
399 def validate_email(self, key, email):
400 # check if this email is not main one
400 # check if this email is not main one
401 main_email = Session().query(User).filter(User.email == email).scalar()
401 main_email = Session().query(User).filter(User.email == email).scalar()
402 if main_email is not None:
402 if main_email is not None:
403 raise AttributeError('email %s is present is user table' % email)
403 raise AttributeError('email %s is present is user table' % email)
404 return email
404 return email
405
405
406 @hybrid_property
406 @hybrid_property
407 def email(self):
407 def email(self):
408 return self._email
408 return self._email
409
409
410 @email.setter
410 @email.setter
411 def email(self, val):
411 def email(self, val):
412 self._email = val.lower() if val else None
412 self._email = val.lower() if val else None
413
413
414
414
415 class UserIpMap(Base, BaseModel):
415 class UserIpMap(Base, BaseModel):
416 __tablename__ = 'user_ip_map'
416 __tablename__ = 'user_ip_map'
417 __table_args__ = (
417 __table_args__ = (
418 UniqueConstraint('user_id', 'ip_addr'),
418 UniqueConstraint('user_id', 'ip_addr'),
419 {'extend_existing': True, 'mysql_engine': 'InnoDB',
419 {'extend_existing': True, 'mysql_engine': 'InnoDB',
420 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
420 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
421 )
421 )
422 __mapper_args__ = {}
422 __mapper_args__ = {}
423
423
424 ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
424 ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
425 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
425 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
426 ip_addr = Column("ip_addr", String(255), nullable=True, unique=False, default=None)
426 ip_addr = Column("ip_addr", String(255), nullable=True, unique=False, default=None)
427 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
427 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
428 user = relationship('User', lazy='joined')
428 user = relationship('User', lazy='joined')
429
429
430
430
431 class UserLog(Base, BaseModel):
431 class UserLog(Base, BaseModel):
432 __tablename__ = 'user_logs'
432 __tablename__ = 'user_logs'
433 __table_args__ = (
433 __table_args__ = (
434 {'extend_existing': True, 'mysql_engine': 'InnoDB',
434 {'extend_existing': True, 'mysql_engine': 'InnoDB',
435 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
435 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
436 )
436 )
437 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
437 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
438 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
438 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
439 username = Column("username", String(255), nullable=True, unique=None, default=None)
439 username = Column("username", String(255), nullable=True, unique=None, default=None)
440 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
440 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
441 repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None)
441 repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None)
442 user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None)
442 user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None)
443 action = Column("action", String(1200000), nullable=True, unique=None, default=None)
443 action = Column("action", String(1200000), nullable=True, unique=None, default=None)
444 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
444 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
445
445
446 def __unicode__(self):
446 def __unicode__(self):
447 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
447 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
448 self.repository_name,
448 self.repository_name,
449 self.action)
449 self.action)
450
450
451 user = relationship('User')
451 user = relationship('User')
452 repository = relationship('Repository', cascade='')
452 repository = relationship('Repository', cascade='')
453
453
454
454
455 class UserGroup(Base, BaseModel):
455 class UserGroup(Base, BaseModel):
456 __tablename__ = 'users_groups'
456 __tablename__ = 'users_groups'
457 __table_args__ = (
457 __table_args__ = (
458 {'extend_existing': True, 'mysql_engine': 'InnoDB',
458 {'extend_existing': True, 'mysql_engine': 'InnoDB',
459 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
459 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
460 )
460 )
461
461
462 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
462 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
463 users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None)
463 users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None)
464 user_group_description = Column("user_group_description", String(10000), nullable=True, unique=None, default=None)
464 user_group_description = Column("user_group_description", String(10000), nullable=True, unique=None, default=None)
465 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
465 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
466 inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
466 inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
467 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
467 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
468 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
468 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
469
469
470 members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
470 members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
471 users_group_to_perm = relationship('UserGroupToPerm', cascade='all')
471 users_group_to_perm = relationship('UserGroupToPerm', cascade='all')
472 users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
472 users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
473 users_group_repo_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
473 users_group_repo_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
474 user_user_group_to_perm = relationship('UserUserGroupToPerm', cascade='all')
474 user_user_group_to_perm = relationship('UserUserGroupToPerm', cascade='all')
475 user_group_user_group_to_perm = relationship('UserGroupUserGroupToPerm ', primaryjoin="UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id", cascade='all')
475 user_group_user_group_to_perm = relationship('UserGroupUserGroupToPerm ', primaryjoin="UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id", cascade='all')
476
476
477 user = relationship('User')
477 user = relationship('User')
478
478
479 def __unicode__(self):
479 def __unicode__(self):
480 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
480 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
481 self.users_group_id,
481 self.users_group_id,
482 self.users_group_name)
482 self.users_group_name)
483
483
484 @classmethod
484 @classmethod
485 def get_by_group_name(cls, group_name, cache=False,
485 def get_by_group_name(cls, group_name, cache=False,
486 case_insensitive=False):
486 case_insensitive=False):
487 if case_insensitive:
487 if case_insensitive:
488 q = cls.query().filter(cls.users_group_name.ilike(group_name))
488 q = cls.query().filter(cls.users_group_name.ilike(group_name))
489 else:
489 else:
490 q = cls.query().filter(cls.users_group_name == group_name)
490 q = cls.query().filter(cls.users_group_name == group_name)
491 if cache:
491 if cache:
492 q = q.options(FromCache(
492 q = q.options(FromCache(
493 "sql_cache_short",
493 "sql_cache_short",
494 "get_user_%s" % _hash_key(group_name)
494 "get_user_%s" % _hash_key(group_name)
495 )
495 )
496 )
496 )
497 return q.scalar()
497 return q.scalar()
498
498
499 @classmethod
499 @classmethod
500 def get(cls, user_group_id, cache=False):
500 def get(cls, user_group_id, cache=False):
501 user_group = cls.query()
501 user_group = cls.query()
502 if cache:
502 if cache:
503 user_group = user_group.options(FromCache("sql_cache_short",
503 user_group = user_group.options(FromCache("sql_cache_short",
504 "get_users_group_%s" % user_group_id))
504 "get_users_group_%s" % user_group_id))
505 return user_group.get(user_group_id)
505 return user_group.get(user_group_id)
506
506
507
507
508 class UserGroupMember(Base, BaseModel):
508 class UserGroupMember(Base, BaseModel):
509 __tablename__ = 'users_groups_members'
509 __tablename__ = 'users_groups_members'
510 __table_args__ = (
510 __table_args__ = (
511 {'extend_existing': True, 'mysql_engine': 'InnoDB',
511 {'extend_existing': True, 'mysql_engine': 'InnoDB',
512 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
512 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
513 )
513 )
514
514
515 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
515 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
516 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
516 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
517 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
517 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
518
518
519 user = relationship('User', lazy='joined')
519 user = relationship('User', lazy='joined')
520 users_group = relationship('UserGroup')
520 users_group = relationship('UserGroup')
521
521
522 def __init__(self, gr_id='', u_id=''):
522 def __init__(self, gr_id='', u_id=''):
523 self.users_group_id = gr_id
523 self.users_group_id = gr_id
524 self.user_id = u_id
524 self.user_id = u_id
525
525
526
526
527 class RepositoryField(Base, BaseModel):
527 class RepositoryField(Base, BaseModel):
528 __tablename__ = 'repositories_fields'
528 __tablename__ = 'repositories_fields'
529 __table_args__ = (
529 __table_args__ = (
530 UniqueConstraint('repository_id', 'field_key'), # no-multi field
530 UniqueConstraint('repository_id', 'field_key'), # no-multi field
531 {'extend_existing': True, 'mysql_engine': 'InnoDB',
531 {'extend_existing': True, 'mysql_engine': 'InnoDB',
532 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
532 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
533 )
533 )
534 PREFIX = 'ex_' # prefix used in form to not conflict with already existing fields
534 PREFIX = 'ex_' # prefix used in form to not conflict with already existing fields
535
535
536 repo_field_id = Column("repo_field_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
536 repo_field_id = Column("repo_field_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
537 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
537 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
538 field_key = Column("field_key", String(250))
538 field_key = Column("field_key", String(250))
539 field_label = Column("field_label", String(1024), nullable=False)
539 field_label = Column("field_label", String(1024), nullable=False)
540 field_value = Column("field_value", String(10000), nullable=False)
540 field_value = Column("field_value", String(10000), nullable=False)
541 field_desc = Column("field_desc", String(1024), nullable=False)
541 field_desc = Column("field_desc", String(1024), nullable=False)
542 field_type = Column("field_type", String(256), nullable=False, unique=None)
542 field_type = Column("field_type", String(256), nullable=False, unique=None)
543 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
543 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
544
544
545 repository = relationship('Repository')
545 repository = relationship('Repository')
546
546
547 @classmethod
547 @classmethod
548 def get_by_key_name(cls, key, repo):
548 def get_by_key_name(cls, key, repo):
549 row = cls.query()\
549 row = cls.query()\
550 .filter(cls.repository == repo)\
550 .filter(cls.repository == repo)\
551 .filter(cls.field_key == key).scalar()
551 .filter(cls.field_key == key).scalar()
552 return row
552 return row
553
553
554
554
555 class Repository(Base, BaseModel):
555 class Repository(Base, BaseModel):
556 __tablename__ = 'repositories'
556 __tablename__ = 'repositories'
557 __table_args__ = (
557 __table_args__ = (
558 UniqueConstraint('repo_name'),
558 UniqueConstraint('repo_name'),
559 Index('r_repo_name_idx', 'repo_name'),
559 Index('r_repo_name_idx', 'repo_name'),
560 {'extend_existing': True, 'mysql_engine': 'InnoDB',
560 {'extend_existing': True, 'mysql_engine': 'InnoDB',
561 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
561 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
562 )
562 )
563
563
564 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
564 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
565 repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None)
565 repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None)
566 clone_uri = Column("clone_uri", String(255), nullable=True, unique=False, default=None)
566 clone_uri = Column("clone_uri", String(255), nullable=True, unique=False, default=None)
567 repo_type = Column("repo_type", String(255), nullable=False, unique=False, default=None)
567 repo_type = Column("repo_type", String(255), nullable=False, unique=False, default=None)
568 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
568 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
569 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
569 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
570 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
570 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
571 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
571 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
572 description = Column("description", String(10000), nullable=True, unique=None, default=None)
572 description = Column("description", String(10000), nullable=True, unique=None, default=None)
573 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
573 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
574 updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
574 updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
575 landing_rev = Column("landing_revision", String(255), nullable=False, unique=False, default=None)
575 landing_rev = Column("landing_revision", String(255), nullable=False, unique=False, default=None)
576 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
576 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
577 _locked = Column("locked", String(255), nullable=True, unique=False, default=None)
577 _locked = Column("locked", String(255), nullable=True, unique=False, default=None)
578 _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) #JSON data
578 _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) #JSON data
579
579
580 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
580 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
581 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
581 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
582
582
583 user = relationship('User')
583 user = relationship('User')
584 fork = relationship('Repository', remote_side=repo_id)
584 fork = relationship('Repository', remote_side=repo_id)
585 group = relationship('RepoGroup')
585 group = relationship('RepoGroup')
586 repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
586 repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
587 users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
587 users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
588 stats = relationship('Statistics', cascade='all', uselist=False)
588 stats = relationship('Statistics', cascade='all', uselist=False)
589
589
590 followers = relationship('UserFollowing',
590 followers = relationship('UserFollowing',
591 primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id',
591 primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id',
592 cascade='all')
592 cascade='all')
593 extra_fields = relationship('RepositoryField',
593 extra_fields = relationship('RepositoryField',
594 cascade="all, delete, delete-orphan")
594 cascade="all, delete, delete-orphan")
595
595
596 logs = relationship('UserLog')
596 logs = relationship('UserLog')
597 comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan")
597 comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan")
598
598
599 pull_requests_org = relationship('PullRequest',
599 pull_requests_org = relationship('PullRequest',
600 primaryjoin='PullRequest.org_repo_id==Repository.repo_id',
600 primaryjoin='PullRequest.org_repo_id==Repository.repo_id',
601 cascade="all, delete, delete-orphan")
601 cascade="all, delete, delete-orphan")
602
602
603 pull_requests_other = relationship('PullRequest',
603 pull_requests_other = relationship('PullRequest',
604 primaryjoin='PullRequest.other_repo_id==Repository.repo_id',
604 primaryjoin='PullRequest.other_repo_id==Repository.repo_id',
605 cascade="all, delete, delete-orphan")
605 cascade="all, delete, delete-orphan")
606
606
607 def __unicode__(self):
607 def __unicode__(self):
608 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id,
608 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id,
609 safe_unicode(self.repo_name))
609 safe_unicode(self.repo_name))
610
610
611 @classmethod
611 @classmethod
612 def get_by_repo_name(cls, repo_name):
612 def get_by_repo_name(cls, repo_name):
613 q = Session().query(cls).filter(cls.repo_name == repo_name)
613 q = Session().query(cls).filter(cls.repo_name == repo_name)
614 q = q.options(joinedload(Repository.fork))\
614 q = q.options(joinedload(Repository.fork))\
615 .options(joinedload(Repository.user))\
615 .options(joinedload(Repository.user))\
616 .options(joinedload(Repository.group))
616 .options(joinedload(Repository.group))
617 return q.scalar()
617 return q.scalar()
618
618
619
619
620 class RepoGroup(Base, BaseModel):
620 class RepoGroup(Base, BaseModel):
621 __tablename__ = 'groups'
621 __tablename__ = 'groups'
622 __table_args__ = (
622 __table_args__ = (
623 UniqueConstraint('group_name', 'group_parent_id'),
623 UniqueConstraint('group_name', 'group_parent_id'),
624 CheckConstraint('group_id != group_parent_id'),
625 {'extend_existing': True, 'mysql_engine': 'InnoDB',
624 {'extend_existing': True, 'mysql_engine': 'InnoDB',
626 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
625 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
627 )
626 )
628 __mapper_args__ = {'order_by': 'group_name'}
627 __mapper_args__ = {'order_by': 'group_name'}
629
628
630 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
629 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
631 group_name = Column("group_name", String(255), nullable=False, unique=True, default=None)
630 group_name = Column("group_name", String(255), nullable=False, unique=True, default=None)
632 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
631 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
633 group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None)
632 group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None)
634 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
633 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
635 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
634 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
636 #TODO: create this field in migrations
635 #TODO: create this field in migrations
637 #created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
636 #created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
638
637
639 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
638 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
640 users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
639 users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
641 parent_group = relationship('RepoGroup', remote_side=group_id)
640 parent_group = relationship('RepoGroup', remote_side=group_id)
642 user = relationship('User')
641 user = relationship('User')
643
642
644 def __init__(self, group_name='', parent_group=None):
643 def __init__(self, group_name='', parent_group=None):
645 self.group_name = group_name
644 self.group_name = group_name
646 self.parent_group = parent_group
645 self.parent_group = parent_group
647
646
648 def __unicode__(self):
647 def __unicode__(self):
649 return u"<%s('id:%s:%s')>" % (self.__class__.__name__, self.group_id,
648 return u"<%s('id:%s:%s')>" % (self.__class__.__name__, self.group_id,
650 self.group_name)
649 self.group_name)
651
650
652 @classmethod
651 @classmethod
653 def url_sep(cls):
652 def url_sep(cls):
654 return URL_SEP
653 return URL_SEP
655
654
656 @classmethod
655 @classmethod
657 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
656 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
658 if case_insensitive:
657 if case_insensitive:
659 gr = cls.query()\
658 gr = cls.query()\
660 .filter(cls.group_name.ilike(group_name))
659 .filter(cls.group_name.ilike(group_name))
661 else:
660 else:
662 gr = cls.query()\
661 gr = cls.query()\
663 .filter(cls.group_name == group_name)
662 .filter(cls.group_name == group_name)
664 if cache:
663 if cache:
665 gr = gr.options(FromCache(
664 gr = gr.options(FromCache(
666 "sql_cache_short",
665 "sql_cache_short",
667 "get_group_%s" % _hash_key(group_name)
666 "get_group_%s" % _hash_key(group_name)
668 )
667 )
669 )
668 )
670 return gr.scalar()
669 return gr.scalar()
671
670
672
671
673 class Permission(Base, BaseModel):
672 class Permission(Base, BaseModel):
674 __tablename__ = 'permissions'
673 __tablename__ = 'permissions'
675 __table_args__ = (
674 __table_args__ = (
676 Index('p_perm_name_idx', 'permission_name'),
675 Index('p_perm_name_idx', 'permission_name'),
677 {'extend_existing': True, 'mysql_engine': 'InnoDB',
676 {'extend_existing': True, 'mysql_engine': 'InnoDB',
678 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
677 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
679 )
678 )
680 PERMS = [
679 PERMS = [
681 ('hg.admin', _('RhodeCode Administrator')),
680 ('hg.admin', _('RhodeCode Administrator')),
682
681
683 ('repository.none', _('Repository no access')),
682 ('repository.none', _('Repository no access')),
684 ('repository.read', _('Repository read access')),
683 ('repository.read', _('Repository read access')),
685 ('repository.write', _('Repository write access')),
684 ('repository.write', _('Repository write access')),
686 ('repository.admin', _('Repository admin access')),
685 ('repository.admin', _('Repository admin access')),
687
686
688 ('group.none', _('Repository group no access')),
687 ('group.none', _('Repository group no access')),
689 ('group.read', _('Repository group read access')),
688 ('group.read', _('Repository group read access')),
690 ('group.write', _('Repository group write access')),
689 ('group.write', _('Repository group write access')),
691 ('group.admin', _('Repository group admin access')),
690 ('group.admin', _('Repository group admin access')),
692
691
693 ('usergroup.none', _('User group no access')),
692 ('usergroup.none', _('User group no access')),
694 ('usergroup.read', _('User group read access')),
693 ('usergroup.read', _('User group read access')),
695 ('usergroup.write', _('User group write access')),
694 ('usergroup.write', _('User group write access')),
696 ('usergroup.admin', _('User group admin access')),
695 ('usergroup.admin', _('User group admin access')),
697
696
698 ('hg.repogroup.create.false', _('Repository Group creation disabled')),
697 ('hg.repogroup.create.false', _('Repository Group creation disabled')),
699 ('hg.repogroup.create.true', _('Repository Group creation enabled')),
698 ('hg.repogroup.create.true', _('Repository Group creation enabled')),
700
699
701 ('hg.usergroup.create.false', _('User Group creation disabled')),
700 ('hg.usergroup.create.false', _('User Group creation disabled')),
702 ('hg.usergroup.create.true', _('User Group creation enabled')),
701 ('hg.usergroup.create.true', _('User Group creation enabled')),
703
702
704 ('hg.create.none', _('Repository creation disabled')),
703 ('hg.create.none', _('Repository creation disabled')),
705 ('hg.create.repository', _('Repository creation enabled')),
704 ('hg.create.repository', _('Repository creation enabled')),
706
705
707 ('hg.fork.none', _('Repository forking disabled')),
706 ('hg.fork.none', _('Repository forking disabled')),
708 ('hg.fork.repository', _('Repository forking enabled')),
707 ('hg.fork.repository', _('Repository forking enabled')),
709
708
710 ('hg.register.none', _('Registration disabled')),
709 ('hg.register.none', _('Registration disabled')),
711 ('hg.register.manual_activate', _('User Registration with manual account activation')),
710 ('hg.register.manual_activate', _('User Registration with manual account activation')),
712 ('hg.register.auto_activate', _('User Registration with automatic account activation')),
711 ('hg.register.auto_activate', _('User Registration with automatic account activation')),
713
712
714 ('hg.extern_activate.manual', _('Manual activation of external account')),
713 ('hg.extern_activate.manual', _('Manual activation of external account')),
715 ('hg.extern_activate.auto', _('Automatic activation of external account')),
714 ('hg.extern_activate.auto', _('Automatic activation of external account')),
716
715
717 ]
716 ]
718
717
719 #definition of system default permissions for DEFAULT user
718 #definition of system default permissions for DEFAULT user
720 DEFAULT_USER_PERMISSIONS = [
719 DEFAULT_USER_PERMISSIONS = [
721 'repository.read',
720 'repository.read',
722 'group.read',
721 'group.read',
723 'usergroup.read',
722 'usergroup.read',
724 'hg.create.repository',
723 'hg.create.repository',
725 'hg.fork.repository',
724 'hg.fork.repository',
726 'hg.register.manual_activate',
725 'hg.register.manual_activate',
727 'hg.extern_activate.auto',
726 'hg.extern_activate.auto',
728 ]
727 ]
729
728
730 # defines which permissions are more important higher the more important
729 # defines which permissions are more important higher the more important
731 # Weight defines which permissions are more important.
730 # Weight defines which permissions are more important.
732 # The higher number the more important.
731 # The higher number the more important.
733 PERM_WEIGHTS = {
732 PERM_WEIGHTS = {
734 'repository.none': 0,
733 'repository.none': 0,
735 'repository.read': 1,
734 'repository.read': 1,
736 'repository.write': 3,
735 'repository.write': 3,
737 'repository.admin': 4,
736 'repository.admin': 4,
738
737
739 'group.none': 0,
738 'group.none': 0,
740 'group.read': 1,
739 'group.read': 1,
741 'group.write': 3,
740 'group.write': 3,
742 'group.admin': 4,
741 'group.admin': 4,
743
742
744 'usergroup.none': 0,
743 'usergroup.none': 0,
745 'usergroup.read': 1,
744 'usergroup.read': 1,
746 'usergroup.write': 3,
745 'usergroup.write': 3,
747 'usergroup.admin': 4,
746 'usergroup.admin': 4,
748 'hg.repogroup.create.false': 0,
747 'hg.repogroup.create.false': 0,
749 'hg.repogroup.create.true': 1,
748 'hg.repogroup.create.true': 1,
750
749
751 'hg.usergroup.create.false': 0,
750 'hg.usergroup.create.false': 0,
752 'hg.usergroup.create.true': 1,
751 'hg.usergroup.create.true': 1,
753
752
754 'hg.fork.none': 0,
753 'hg.fork.none': 0,
755 'hg.fork.repository': 1,
754 'hg.fork.repository': 1,
756 'hg.create.none': 0,
755 'hg.create.none': 0,
757 'hg.create.repository': 1
756 'hg.create.repository': 1
758 }
757 }
759
758
760 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
759 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
761 permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None)
760 permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None)
762 permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None)
761 permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None)
763
762
764 def __unicode__(self):
763 def __unicode__(self):
765 return u"<%s('%s:%s')>" % (
764 return u"<%s('%s:%s')>" % (
766 self.__class__.__name__, self.permission_id, self.permission_name
765 self.__class__.__name__, self.permission_id, self.permission_name
767 )
766 )
768
767
769 @classmethod
768 @classmethod
770 def get_by_key(cls, key):
769 def get_by_key(cls, key):
771 return cls.query().filter(cls.permission_name == key).scalar()
770 return cls.query().filter(cls.permission_name == key).scalar()
772
771
773
772
774 class UserRepoToPerm(Base, BaseModel):
773 class UserRepoToPerm(Base, BaseModel):
775 __tablename__ = 'repo_to_perm'
774 __tablename__ = 'repo_to_perm'
776 __table_args__ = (
775 __table_args__ = (
777 UniqueConstraint('user_id', 'repository_id', 'permission_id'),
776 UniqueConstraint('user_id', 'repository_id', 'permission_id'),
778 {'extend_existing': True, 'mysql_engine': 'InnoDB',
777 {'extend_existing': True, 'mysql_engine': 'InnoDB',
779 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
778 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
780 )
779 )
781 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
780 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
782 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
781 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
783 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
782 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
784 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
783 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
785
784
786 user = relationship('User')
785 user = relationship('User')
787 repository = relationship('Repository')
786 repository = relationship('Repository')
788 permission = relationship('Permission')
787 permission = relationship('Permission')
789
788
790 def __unicode__(self):
789 def __unicode__(self):
791 return u'<%s => %s >' % (self.user, self.repository)
790 return u'<%s => %s >' % (self.user, self.repository)
792
791
793
792
794 class UserUserGroupToPerm(Base, BaseModel):
793 class UserUserGroupToPerm(Base, BaseModel):
795 __tablename__ = 'user_user_group_to_perm'
794 __tablename__ = 'user_user_group_to_perm'
796 __table_args__ = (
795 __table_args__ = (
797 UniqueConstraint('user_id', 'user_group_id', 'permission_id'),
796 UniqueConstraint('user_id', 'user_group_id', 'permission_id'),
798 {'extend_existing': True, 'mysql_engine': 'InnoDB',
797 {'extend_existing': True, 'mysql_engine': 'InnoDB',
799 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
798 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
800 )
799 )
801 user_user_group_to_perm_id = Column("user_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
800 user_user_group_to_perm_id = Column("user_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
802 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
801 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
803 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
802 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
804 user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
803 user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
805
804
806 user = relationship('User')
805 user = relationship('User')
807 user_group = relationship('UserGroup')
806 user_group = relationship('UserGroup')
808 permission = relationship('Permission')
807 permission = relationship('Permission')
809
808
810 def __unicode__(self):
809 def __unicode__(self):
811 return u'<%s => %s >' % (self.user, self.user_group)
810 return u'<%s => %s >' % (self.user, self.user_group)
812
811
813
812
814 class UserToPerm(Base, BaseModel):
813 class UserToPerm(Base, BaseModel):
815 __tablename__ = 'user_to_perm'
814 __tablename__ = 'user_to_perm'
816 __table_args__ = (
815 __table_args__ = (
817 UniqueConstraint('user_id', 'permission_id'),
816 UniqueConstraint('user_id', 'permission_id'),
818 {'extend_existing': True, 'mysql_engine': 'InnoDB',
817 {'extend_existing': True, 'mysql_engine': 'InnoDB',
819 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
818 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
820 )
819 )
821 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
820 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
822 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
821 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
823 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
822 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
824
823
825 user = relationship('User')
824 user = relationship('User')
826 permission = relationship('Permission', lazy='joined')
825 permission = relationship('Permission', lazy='joined')
827
826
828 def __unicode__(self):
827 def __unicode__(self):
829 return u'<%s => %s >' % (self.user, self.permission)
828 return u'<%s => %s >' % (self.user, self.permission)
830
829
831
830
832 class UserGroupRepoToPerm(Base, BaseModel):
831 class UserGroupRepoToPerm(Base, BaseModel):
833 __tablename__ = 'users_group_repo_to_perm'
832 __tablename__ = 'users_group_repo_to_perm'
834 __table_args__ = (
833 __table_args__ = (
835 UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
834 UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
836 {'extend_existing': True, 'mysql_engine': 'InnoDB',
835 {'extend_existing': True, 'mysql_engine': 'InnoDB',
837 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
836 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
838 )
837 )
839 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
838 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
840 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
839 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
841 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
840 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
842 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
841 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
843
842
844 users_group = relationship('UserGroup')
843 users_group = relationship('UserGroup')
845 permission = relationship('Permission')
844 permission = relationship('Permission')
846 repository = relationship('Repository')
845 repository = relationship('Repository')
847
846
848 def __unicode__(self):
847 def __unicode__(self):
849 return u'<UserGroupRepoToPerm:%s => %s >' % (self.users_group, self.repository)
848 return u'<UserGroupRepoToPerm:%s => %s >' % (self.users_group, self.repository)
850
849
851
850
852 class UserGroupUserGroupToPerm(Base, BaseModel):
851 class UserGroupUserGroupToPerm(Base, BaseModel):
853 __tablename__ = 'user_group_user_group_to_perm'
852 __tablename__ = 'user_group_user_group_to_perm'
854 __table_args__ = (
853 __table_args__ = (
855 UniqueConstraint('target_user_group_id', 'user_group_id', 'permission_id'),
854 UniqueConstraint('target_user_group_id', 'user_group_id', 'permission_id'),
856 CheckConstraint('target_user_group_id != user_group_id'),
855 CheckConstraint('target_user_group_id != user_group_id'),
857 {'extend_existing': True, 'mysql_engine': 'InnoDB',
856 {'extend_existing': True, 'mysql_engine': 'InnoDB',
858 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
857 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
859 )
858 )
860 user_group_user_group_to_perm_id = Column("user_group_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
859 user_group_user_group_to_perm_id = Column("user_group_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
861 target_user_group_id = Column("target_user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
860 target_user_group_id = Column("target_user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
862 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
861 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
863 user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
862 user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
864
863
865 target_user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id')
864 target_user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id')
866 user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.user_group_id==UserGroup.users_group_id')
865 user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.user_group_id==UserGroup.users_group_id')
867 permission = relationship('Permission')
866 permission = relationship('Permission')
868
867
869 def __unicode__(self):
868 def __unicode__(self):
870 return u'<UserGroupUserGroup:%s => %s >' % (self.target_user_group, self.user_group)
869 return u'<UserGroupUserGroup:%s => %s >' % (self.target_user_group, self.user_group)
871
870
872
871
873 class UserGroupToPerm(Base, BaseModel):
872 class UserGroupToPerm(Base, BaseModel):
874 __tablename__ = 'users_group_to_perm'
873 __tablename__ = 'users_group_to_perm'
875 __table_args__ = (
874 __table_args__ = (
876 UniqueConstraint('users_group_id', 'permission_id',),
875 UniqueConstraint('users_group_id', 'permission_id',),
877 {'extend_existing': True, 'mysql_engine': 'InnoDB',
876 {'extend_existing': True, 'mysql_engine': 'InnoDB',
878 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
877 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
879 )
878 )
880 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
879 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
881 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
880 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
882 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
881 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
883
882
884 users_group = relationship('UserGroup')
883 users_group = relationship('UserGroup')
885 permission = relationship('Permission')
884 permission = relationship('Permission')
886
885
887
886
888 class UserRepoGroupToPerm(Base, BaseModel):
887 class UserRepoGroupToPerm(Base, BaseModel):
889 __tablename__ = 'user_repo_group_to_perm'
888 __tablename__ = 'user_repo_group_to_perm'
890 __table_args__ = (
889 __table_args__ = (
891 UniqueConstraint('user_id', 'group_id', 'permission_id'),
890 UniqueConstraint('user_id', 'group_id', 'permission_id'),
892 {'extend_existing': True, 'mysql_engine': 'InnoDB',
891 {'extend_existing': True, 'mysql_engine': 'InnoDB',
893 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
892 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
894 )
893 )
895
894
896 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
895 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
897 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
896 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
898 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
897 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
899 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
898 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
900
899
901 user = relationship('User')
900 user = relationship('User')
902 group = relationship('RepoGroup')
901 group = relationship('RepoGroup')
903 permission = relationship('Permission')
902 permission = relationship('Permission')
904
903
905
904
906 class UserGroupRepoGroupToPerm(Base, BaseModel):
905 class UserGroupRepoGroupToPerm(Base, BaseModel):
907 __tablename__ = 'users_group_repo_group_to_perm'
906 __tablename__ = 'users_group_repo_group_to_perm'
908 __table_args__ = (
907 __table_args__ = (
909 UniqueConstraint('users_group_id', 'group_id'),
908 UniqueConstraint('users_group_id', 'group_id'),
910 {'extend_existing': True, 'mysql_engine': 'InnoDB',
909 {'extend_existing': True, 'mysql_engine': 'InnoDB',
911 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
910 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
912 )
911 )
913
912
914 users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
913 users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
915 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
914 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
916 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
915 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
917 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
916 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
918
917
919 users_group = relationship('UserGroup')
918 users_group = relationship('UserGroup')
920 permission = relationship('Permission')
919 permission = relationship('Permission')
921 group = relationship('RepoGroup')
920 group = relationship('RepoGroup')
922
921
923
922
924 class Statistics(Base, BaseModel):
923 class Statistics(Base, BaseModel):
925 __tablename__ = 'statistics'
924 __tablename__ = 'statistics'
926 __table_args__ = (
925 __table_args__ = (
927 UniqueConstraint('repository_id'),
926 UniqueConstraint('repository_id'),
928 {'extend_existing': True, 'mysql_engine': 'InnoDB',
927 {'extend_existing': True, 'mysql_engine': 'InnoDB',
929 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
928 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
930 )
929 )
931 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
930 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
932 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
931 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
933 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
932 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
934 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
933 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
935 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
934 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
936 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
935 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
937
936
938 repository = relationship('Repository', single_parent=True)
937 repository = relationship('Repository', single_parent=True)
939
938
940
939
941 class UserFollowing(Base, BaseModel):
940 class UserFollowing(Base, BaseModel):
942 __tablename__ = 'user_followings'
941 __tablename__ = 'user_followings'
943 __table_args__ = (
942 __table_args__ = (
944 UniqueConstraint('user_id', 'follows_repository_id'),
943 UniqueConstraint('user_id', 'follows_repository_id'),
945 UniqueConstraint('user_id', 'follows_user_id'),
944 UniqueConstraint('user_id', 'follows_user_id'),
946 {'extend_existing': True, 'mysql_engine': 'InnoDB',
945 {'extend_existing': True, 'mysql_engine': 'InnoDB',
947 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
946 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
948 )
947 )
949
948
950 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
949 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
951 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
950 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
952 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
951 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
953 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
952 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
954 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
953 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
955
954
956 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
955 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
957
956
958 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
957 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
959 follows_repository = relationship('Repository', order_by='Repository.repo_name')
958 follows_repository = relationship('Repository', order_by='Repository.repo_name')
960
959
961
960
962 class CacheInvalidation(Base, BaseModel):
961 class CacheInvalidation(Base, BaseModel):
963 __tablename__ = 'cache_invalidation'
962 __tablename__ = 'cache_invalidation'
964 __table_args__ = (
963 __table_args__ = (
965 UniqueConstraint('cache_key'),
964 UniqueConstraint('cache_key'),
966 Index('key_idx', 'cache_key'),
965 Index('key_idx', 'cache_key'),
967 {'extend_existing': True, 'mysql_engine': 'InnoDB',
966 {'extend_existing': True, 'mysql_engine': 'InnoDB',
968 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
967 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
969 )
968 )
970 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
969 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
971 cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None)
970 cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None)
972 cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None)
971 cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None)
973 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
972 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
974
973
975 def __init__(self, cache_key, cache_args=''):
974 def __init__(self, cache_key, cache_args=''):
976 self.cache_key = cache_key
975 self.cache_key = cache_key
977 self.cache_args = cache_args
976 self.cache_args = cache_args
978 self.cache_active = False
977 self.cache_active = False
979
978
980
979
981 class ChangesetComment(Base, BaseModel):
980 class ChangesetComment(Base, BaseModel):
982 __tablename__ = 'changeset_comments'
981 __tablename__ = 'changeset_comments'
983 __table_args__ = (
982 __table_args__ = (
984 Index('cc_revision_idx', 'revision'),
983 Index('cc_revision_idx', 'revision'),
985 {'extend_existing': True, 'mysql_engine': 'InnoDB',
984 {'extend_existing': True, 'mysql_engine': 'InnoDB',
986 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
985 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
987 )
986 )
988 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
987 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
989 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
988 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
990 revision = Column('revision', String(40), nullable=True)
989 revision = Column('revision', String(40), nullable=True)
991 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
990 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
992 line_no = Column('line_no', Unicode(10), nullable=True)
991 line_no = Column('line_no', Unicode(10), nullable=True)
993 hl_lines = Column('hl_lines', Unicode(512), nullable=True)
992 hl_lines = Column('hl_lines', Unicode(512), nullable=True)
994 f_path = Column('f_path', Unicode(1000), nullable=True)
993 f_path = Column('f_path', Unicode(1000), nullable=True)
995 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
994 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
996 text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False)
995 text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False)
997 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
996 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
998 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
997 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
999
998
1000 author = relationship('User', lazy='joined')
999 author = relationship('User', lazy='joined')
1001 repo = relationship('Repository')
1000 repo = relationship('Repository')
1002 status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan")
1001 status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan")
1003 pull_request = relationship('PullRequest', lazy='joined')
1002 pull_request = relationship('PullRequest', lazy='joined')
1004
1003
1005
1004
1006 class ChangesetStatus(Base, BaseModel):
1005 class ChangesetStatus(Base, BaseModel):
1007 __tablename__ = 'changeset_statuses'
1006 __tablename__ = 'changeset_statuses'
1008 __table_args__ = (
1007 __table_args__ = (
1009 Index('cs_revision_idx', 'revision'),
1008 Index('cs_revision_idx', 'revision'),
1010 Index('cs_version_idx', 'version'),
1009 Index('cs_version_idx', 'version'),
1011 UniqueConstraint('repo_id', 'revision', 'version'),
1010 UniqueConstraint('repo_id', 'revision', 'version'),
1012 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1011 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1013 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1012 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1014 )
1013 )
1015 STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed'
1014 STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed'
1016 STATUS_APPROVED = 'approved'
1015 STATUS_APPROVED = 'approved'
1017 STATUS_REJECTED = 'rejected'
1016 STATUS_REJECTED = 'rejected'
1018 STATUS_UNDER_REVIEW = 'under_review'
1017 STATUS_UNDER_REVIEW = 'under_review'
1019
1018
1020 STATUSES = [
1019 STATUSES = [
1021 (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default
1020 (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default
1022 (STATUS_APPROVED, _("Approved")),
1021 (STATUS_APPROVED, _("Approved")),
1023 (STATUS_REJECTED, _("Rejected")),
1022 (STATUS_REJECTED, _("Rejected")),
1024 (STATUS_UNDER_REVIEW, _("Under Review")),
1023 (STATUS_UNDER_REVIEW, _("Under Review")),
1025 ]
1024 ]
1026
1025
1027 changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True)
1026 changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True)
1028 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1027 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1029 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1028 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1030 revision = Column('revision', String(40), nullable=False)
1029 revision = Column('revision', String(40), nullable=False)
1031 status = Column('status', String(128), nullable=False, default=DEFAULT)
1030 status = Column('status', String(128), nullable=False, default=DEFAULT)
1032 changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id'))
1031 changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id'))
1033 modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
1032 modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
1034 version = Column('version', Integer(), nullable=False, default=0)
1033 version = Column('version', Integer(), nullable=False, default=0)
1035 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
1034 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
1036
1035
1037 author = relationship('User', lazy='joined')
1036 author = relationship('User', lazy='joined')
1038 repo = relationship('Repository')
1037 repo = relationship('Repository')
1039 comment = relationship('ChangesetComment', lazy='joined')
1038 comment = relationship('ChangesetComment', lazy='joined')
1040 pull_request = relationship('PullRequest', lazy='joined')
1039 pull_request = relationship('PullRequest', lazy='joined')
1041
1040
1042
1041
1043
1042
1044 class PullRequest(Base, BaseModel):
1043 class PullRequest(Base, BaseModel):
1045 __tablename__ = 'pull_requests'
1044 __tablename__ = 'pull_requests'
1046 __table_args__ = (
1045 __table_args__ = (
1047 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1046 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1048 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1047 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1049 )
1048 )
1050
1049
1051 STATUS_NEW = u'new'
1050 STATUS_NEW = u'new'
1052 STATUS_OPEN = u'open'
1051 STATUS_OPEN = u'open'
1053 STATUS_CLOSED = u'closed'
1052 STATUS_CLOSED = u'closed'
1054
1053
1055 pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True)
1054 pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True)
1056 title = Column('title', Unicode(256), nullable=True)
1055 title = Column('title', Unicode(256), nullable=True)
1057 description = Column('description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), nullable=True)
1056 description = Column('description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), nullable=True)
1058 status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW)
1057 status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW)
1059 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1058 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1060 updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1059 updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1061 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1060 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1062 _revisions = Column('revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql'))
1061 _revisions = Column('revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql'))
1063 org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1062 org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1064 org_ref = Column('org_ref', Unicode(256), nullable=False)
1063 org_ref = Column('org_ref', Unicode(256), nullable=False)
1065 other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1064 other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1066 other_ref = Column('other_ref', Unicode(256), nullable=False)
1065 other_ref = Column('other_ref', Unicode(256), nullable=False)
1067
1066
1068 author = relationship('User', lazy='joined')
1067 author = relationship('User', lazy='joined')
1069 reviewers = relationship('PullRequestReviewers',
1068 reviewers = relationship('PullRequestReviewers',
1070 cascade="all, delete, delete-orphan")
1069 cascade="all, delete, delete-orphan")
1071 org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id')
1070 org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id')
1072 other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id')
1071 other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id')
1073 statuses = relationship('ChangesetStatus')
1072 statuses = relationship('ChangesetStatus')
1074 comments = relationship('ChangesetComment',
1073 comments = relationship('ChangesetComment',
1075 cascade="all, delete, delete-orphan")
1074 cascade="all, delete, delete-orphan")
1076
1075
1077
1076
1078 class PullRequestReviewers(Base, BaseModel):
1077 class PullRequestReviewers(Base, BaseModel):
1079 __tablename__ = 'pull_request_reviewers'
1078 __tablename__ = 'pull_request_reviewers'
1080 __table_args__ = (
1079 __table_args__ = (
1081 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1080 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1082 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1081 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1083 )
1082 )
1084
1083
1085 def __init__(self, user=None, pull_request=None):
1084 def __init__(self, user=None, pull_request=None):
1086 self.user = user
1085 self.user = user
1087 self.pull_request = pull_request
1086 self.pull_request = pull_request
1088
1087
1089 pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True)
1088 pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True)
1090 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False)
1089 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False)
1091 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True)
1090 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True)
1092
1091
1093 user = relationship('User')
1092 user = relationship('User')
1094 pull_request = relationship('PullRequest')
1093 pull_request = relationship('PullRequest')
1095
1094
1096
1095
1097 class Notification(Base, BaseModel):
1096 class Notification(Base, BaseModel):
1098 __tablename__ = 'notifications'
1097 __tablename__ = 'notifications'
1099 __table_args__ = (
1098 __table_args__ = (
1100 Index('notification_type_idx', 'type'),
1099 Index('notification_type_idx', 'type'),
1101 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1100 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1102 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1101 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1103 )
1102 )
1104
1103
1105 TYPE_CHANGESET_COMMENT = u'cs_comment'
1104 TYPE_CHANGESET_COMMENT = u'cs_comment'
1106 TYPE_MESSAGE = u'message'
1105 TYPE_MESSAGE = u'message'
1107 TYPE_MENTION = u'mention'
1106 TYPE_MENTION = u'mention'
1108 TYPE_REGISTRATION = u'registration'
1107 TYPE_REGISTRATION = u'registration'
1109 TYPE_PULL_REQUEST = u'pull_request'
1108 TYPE_PULL_REQUEST = u'pull_request'
1110 TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment'
1109 TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment'
1111
1110
1112 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
1111 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
1113 subject = Column('subject', Unicode(512), nullable=True)
1112 subject = Column('subject', Unicode(512), nullable=True)
1114 body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True)
1113 body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True)
1115 created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
1114 created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
1116 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1115 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1117 type_ = Column('type', Unicode(256))
1116 type_ = Column('type', Unicode(256))
1118
1117
1119 created_by_user = relationship('User')
1118 created_by_user = relationship('User')
1120 notifications_to_users = relationship('UserNotification', lazy='joined',
1119 notifications_to_users = relationship('UserNotification', lazy='joined',
1121 cascade="all, delete, delete-orphan")
1120 cascade="all, delete, delete-orphan")
1122
1121
1123
1122
1124 class UserNotification(Base, BaseModel):
1123 class UserNotification(Base, BaseModel):
1125 __tablename__ = 'user_to_notification'
1124 __tablename__ = 'user_to_notification'
1126 __table_args__ = (
1125 __table_args__ = (
1127 UniqueConstraint('user_id', 'notification_id'),
1126 UniqueConstraint('user_id', 'notification_id'),
1128 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1127 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1129 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1128 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1130 )
1129 )
1131 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
1130 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
1132 notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
1131 notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
1133 read = Column('read', Boolean, default=False)
1132 read = Column('read', Boolean, default=False)
1134 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
1133 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
1135
1134
1136 user = relationship('User', lazy="joined")
1135 user = relationship('User', lazy="joined")
1137 notification = relationship('Notification', lazy="joined",
1136 notification = relationship('Notification', lazy="joined",
1138 order_by=lambda: Notification.created_on.desc(),)
1137 order_by=lambda: Notification.created_on.desc(),)
1139
1138
1140
1139
1141 class Gist(Base, BaseModel):
1140 class Gist(Base, BaseModel):
1142 __tablename__ = 'gists'
1141 __tablename__ = 'gists'
1143 __table_args__ = (
1142 __table_args__ = (
1144 Index('g_gist_access_id_idx', 'gist_access_id'),
1143 Index('g_gist_access_id_idx', 'gist_access_id'),
1145 Index('g_created_on_idx', 'created_on'),
1144 Index('g_created_on_idx', 'created_on'),
1146 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1145 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1147 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1146 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1148 )
1147 )
1149 GIST_PUBLIC = u'public'
1148 GIST_PUBLIC = u'public'
1150 GIST_PRIVATE = u'private'
1149 GIST_PRIVATE = u'private'
1151
1150
1152 gist_id = Column('gist_id', Integer(), primary_key=True)
1151 gist_id = Column('gist_id', Integer(), primary_key=True)
1153 gist_access_id = Column('gist_access_id', Unicode(250))
1152 gist_access_id = Column('gist_access_id', Unicode(250))
1154 gist_description = Column('gist_description', UnicodeText().with_variant(UnicodeText(1024), 'mysql'))
1153 gist_description = Column('gist_description', UnicodeText().with_variant(UnicodeText(1024), 'mysql'))
1155 gist_owner = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=True)
1154 gist_owner = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=True)
1156 gist_expires = Column('gist_expires', Float(53), nullable=False)
1155 gist_expires = Column('gist_expires', Float(53), nullable=False)
1157 gist_type = Column('gist_type', Unicode(128), nullable=False)
1156 gist_type = Column('gist_type', Unicode(128), nullable=False)
1158 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1157 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1159 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1158 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1160
1159
1161 owner = relationship('User')
1160 owner = relationship('User')
1162
1161
1163
1162
1164 class DbMigrateVersion(Base, BaseModel):
1163 class DbMigrateVersion(Base, BaseModel):
1165 __tablename__ = 'db_migrate_version'
1164 __tablename__ = 'db_migrate_version'
1166 __table_args__ = (
1165 __table_args__ = (
1167 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1166 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1168 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1167 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1169 )
1168 )
1170 repository_id = Column('repository_id', String(250), primary_key=True)
1169 repository_id = Column('repository_id', String(250), primary_key=True)
1171 repository_path = Column('repository_path', Text)
1170 repository_path = Column('repository_path', Text)
1172 version = Column('version', Integer)
1171 version = Column('version', Integer)
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now