##// END OF EJS Templates
fixed mysql issues with index
marcink -
r3869:5cf8947d beta
parent child Browse files
Show More
@@ -1,2223 +1,2223 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.model.db
3 rhodecode.model.db
4 ~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~
5
5
6 Database Models for RhodeCode
6 Database Models for RhodeCode
7
7
8 :created_on: Apr 08, 2010
8 :created_on: Apr 08, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import os
26 import os
27 import time
27 import time
28 import logging
28 import logging
29 import datetime
29 import datetime
30 import traceback
30 import traceback
31 import hashlib
31 import hashlib
32 import collections
32 import collections
33
33
34 from sqlalchemy import *
34 from sqlalchemy import *
35 from sqlalchemy.ext.hybrid import hybrid_property
35 from sqlalchemy.ext.hybrid import hybrid_property
36 from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
36 from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
37 from sqlalchemy.exc import DatabaseError
37 from sqlalchemy.exc import DatabaseError
38 from beaker.cache import cache_region, region_invalidate
38 from beaker.cache import cache_region, region_invalidate
39 from webob.exc import HTTPNotFound
39 from webob.exc import HTTPNotFound
40
40
41 from pylons.i18n.translation import lazy_ugettext as _
41 from pylons.i18n.translation import lazy_ugettext as _
42
42
43 from rhodecode.lib.vcs import get_backend
43 from rhodecode.lib.vcs import get_backend
44 from rhodecode.lib.vcs.utils.helpers import get_scm
44 from rhodecode.lib.vcs.utils.helpers import get_scm
45 from rhodecode.lib.vcs.exceptions import VCSError
45 from rhodecode.lib.vcs.exceptions import VCSError
46 from rhodecode.lib.vcs.utils.lazy import LazyProperty
46 from rhodecode.lib.vcs.utils.lazy import LazyProperty
47 from rhodecode.lib.vcs.backends.base import EmptyChangeset
47 from rhodecode.lib.vcs.backends.base import EmptyChangeset
48
48
49 from rhodecode.lib.utils2 import str2bool, safe_str, get_changeset_safe, \
49 from rhodecode.lib.utils2 import str2bool, safe_str, get_changeset_safe, \
50 safe_unicode, remove_suffix, remove_prefix, time_to_datetime, _set_extras
50 safe_unicode, remove_suffix, remove_prefix, time_to_datetime, _set_extras
51 from rhodecode.lib.compat import json
51 from rhodecode.lib.compat import json
52 from rhodecode.lib.caching_query import FromCache
52 from rhodecode.lib.caching_query import FromCache
53
53
54 from rhodecode.model.meta import Base, Session
54 from rhodecode.model.meta import Base, Session
55
55
56 URL_SEP = '/'
56 URL_SEP = '/'
57 log = logging.getLogger(__name__)
57 log = logging.getLogger(__name__)
58
58
59 #==============================================================================
59 #==============================================================================
60 # BASE CLASSES
60 # BASE CLASSES
61 #==============================================================================
61 #==============================================================================
62
62
63 _hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest()
63 _hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest()
64
64
65
65
66 class BaseModel(object):
66 class BaseModel(object):
67 """
67 """
68 Base Model for all classess
68 Base Model for all classess
69 """
69 """
70
70
71 @classmethod
71 @classmethod
72 def _get_keys(cls):
72 def _get_keys(cls):
73 """return column names for this model """
73 """return column names for this model """
74 return class_mapper(cls).c.keys()
74 return class_mapper(cls).c.keys()
75
75
76 def get_dict(self):
76 def get_dict(self):
77 """
77 """
78 return dict with keys and values corresponding
78 return dict with keys and values corresponding
79 to this model data """
79 to this model data """
80
80
81 d = {}
81 d = {}
82 for k in self._get_keys():
82 for k in self._get_keys():
83 d[k] = getattr(self, k)
83 d[k] = getattr(self, k)
84
84
85 # also use __json__() if present to get additional fields
85 # also use __json__() if present to get additional fields
86 _json_attr = getattr(self, '__json__', None)
86 _json_attr = getattr(self, '__json__', None)
87 if _json_attr:
87 if _json_attr:
88 # update with attributes from __json__
88 # update with attributes from __json__
89 if callable(_json_attr):
89 if callable(_json_attr):
90 _json_attr = _json_attr()
90 _json_attr = _json_attr()
91 for k, val in _json_attr.iteritems():
91 for k, val in _json_attr.iteritems():
92 d[k] = val
92 d[k] = val
93 return d
93 return d
94
94
95 def get_appstruct(self):
95 def get_appstruct(self):
96 """return list with keys and values tupples corresponding
96 """return list with keys and values tupples corresponding
97 to this model data """
97 to this model data """
98
98
99 l = []
99 l = []
100 for k in self._get_keys():
100 for k in self._get_keys():
101 l.append((k, getattr(self, k),))
101 l.append((k, getattr(self, k),))
102 return l
102 return l
103
103
104 def populate_obj(self, populate_dict):
104 def populate_obj(self, populate_dict):
105 """populate model with data from given populate_dict"""
105 """populate model with data from given populate_dict"""
106
106
107 for k in self._get_keys():
107 for k in self._get_keys():
108 if k in populate_dict:
108 if k in populate_dict:
109 setattr(self, k, populate_dict[k])
109 setattr(self, k, populate_dict[k])
110
110
111 @classmethod
111 @classmethod
112 def query(cls):
112 def query(cls):
113 return Session().query(cls)
113 return Session().query(cls)
114
114
115 @classmethod
115 @classmethod
116 def get(cls, id_):
116 def get(cls, id_):
117 if id_:
117 if id_:
118 return cls.query().get(id_)
118 return cls.query().get(id_)
119
119
120 @classmethod
120 @classmethod
121 def get_or_404(cls, id_):
121 def get_or_404(cls, id_):
122 try:
122 try:
123 id_ = int(id_)
123 id_ = int(id_)
124 except (TypeError, ValueError):
124 except (TypeError, ValueError):
125 raise HTTPNotFound
125 raise HTTPNotFound
126
126
127 res = cls.query().get(id_)
127 res = cls.query().get(id_)
128 if not res:
128 if not res:
129 raise HTTPNotFound
129 raise HTTPNotFound
130 return res
130 return res
131
131
132 @classmethod
132 @classmethod
133 def getAll(cls):
133 def getAll(cls):
134 # deprecated and left for backward compatibility
134 # deprecated and left for backward compatibility
135 return cls.get_all()
135 return cls.get_all()
136
136
137 @classmethod
137 @classmethod
138 def get_all(cls):
138 def get_all(cls):
139 return cls.query().all()
139 return cls.query().all()
140
140
141 @classmethod
141 @classmethod
142 def delete(cls, id_):
142 def delete(cls, id_):
143 obj = cls.query().get(id_)
143 obj = cls.query().get(id_)
144 Session().delete(obj)
144 Session().delete(obj)
145
145
146 def __repr__(self):
146 def __repr__(self):
147 if hasattr(self, '__unicode__'):
147 if hasattr(self, '__unicode__'):
148 # python repr needs to return str
148 # python repr needs to return str
149 return safe_str(self.__unicode__())
149 return safe_str(self.__unicode__())
150 return '<DB:%s>' % (self.__class__.__name__)
150 return '<DB:%s>' % (self.__class__.__name__)
151
151
152
152
153 class RhodeCodeSetting(Base, BaseModel):
153 class RhodeCodeSetting(Base, BaseModel):
154 __tablename__ = 'rhodecode_settings'
154 __tablename__ = 'rhodecode_settings'
155 __table_args__ = (
155 __table_args__ = (
156 UniqueConstraint('app_settings_name'),
156 UniqueConstraint('app_settings_name'),
157 {'extend_existing': True, 'mysql_engine': 'InnoDB',
157 {'extend_existing': True, 'mysql_engine': 'InnoDB',
158 'mysql_charset': 'utf8'}
158 'mysql_charset': 'utf8'}
159 )
159 )
160 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
160 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
161 app_settings_name = Column("app_settings_name", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
161 app_settings_name = Column("app_settings_name", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
162 _app_settings_value = Column("app_settings_value", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
162 _app_settings_value = Column("app_settings_value", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
163
163
164 def __init__(self, k='', v=''):
164 def __init__(self, k='', v=''):
165 self.app_settings_name = k
165 self.app_settings_name = k
166 self.app_settings_value = v
166 self.app_settings_value = v
167
167
168 @validates('_app_settings_value')
168 @validates('_app_settings_value')
169 def validate_settings_value(self, key, val):
169 def validate_settings_value(self, key, val):
170 assert type(val) == unicode
170 assert type(val) == unicode
171 return val
171 return val
172
172
173 @hybrid_property
173 @hybrid_property
174 def app_settings_value(self):
174 def app_settings_value(self):
175 v = self._app_settings_value
175 v = self._app_settings_value
176 if self.app_settings_name in ["ldap_active",
176 if self.app_settings_name in ["ldap_active",
177 "default_repo_enable_statistics",
177 "default_repo_enable_statistics",
178 "default_repo_enable_locking",
178 "default_repo_enable_locking",
179 "default_repo_private",
179 "default_repo_private",
180 "default_repo_enable_downloads"]:
180 "default_repo_enable_downloads"]:
181 v = str2bool(v)
181 v = str2bool(v)
182 return v
182 return v
183
183
184 @app_settings_value.setter
184 @app_settings_value.setter
185 def app_settings_value(self, val):
185 def app_settings_value(self, val):
186 """
186 """
187 Setter that will always make sure we use unicode in app_settings_value
187 Setter that will always make sure we use unicode in app_settings_value
188
188
189 :param val:
189 :param val:
190 """
190 """
191 self._app_settings_value = safe_unicode(val)
191 self._app_settings_value = safe_unicode(val)
192
192
193 def __unicode__(self):
193 def __unicode__(self):
194 return u"<%s('%s:%s')>" % (
194 return u"<%s('%s:%s')>" % (
195 self.__class__.__name__,
195 self.__class__.__name__,
196 self.app_settings_name, self.app_settings_value
196 self.app_settings_name, self.app_settings_value
197 )
197 )
198
198
199 @classmethod
199 @classmethod
200 def get_by_name(cls, key):
200 def get_by_name(cls, key):
201 return cls.query()\
201 return cls.query()\
202 .filter(cls.app_settings_name == key).scalar()
202 .filter(cls.app_settings_name == key).scalar()
203
203
204 @classmethod
204 @classmethod
205 def get_by_name_or_create(cls, key):
205 def get_by_name_or_create(cls, key):
206 res = cls.get_by_name(key)
206 res = cls.get_by_name(key)
207 if not res:
207 if not res:
208 res = cls(key)
208 res = cls(key)
209 return res
209 return res
210
210
211 @classmethod
211 @classmethod
212 def get_app_settings(cls, cache=False):
212 def get_app_settings(cls, cache=False):
213
213
214 ret = cls.query()
214 ret = cls.query()
215
215
216 if cache:
216 if cache:
217 ret = ret.options(FromCache("sql_cache_short", "get_hg_settings"))
217 ret = ret.options(FromCache("sql_cache_short", "get_hg_settings"))
218
218
219 if not ret:
219 if not ret:
220 raise Exception('Could not get application settings !')
220 raise Exception('Could not get application settings !')
221 settings = {}
221 settings = {}
222 for each in ret:
222 for each in ret:
223 settings['rhodecode_' + each.app_settings_name] = \
223 settings['rhodecode_' + each.app_settings_name] = \
224 each.app_settings_value
224 each.app_settings_value
225
225
226 return settings
226 return settings
227
227
228 @classmethod
228 @classmethod
229 def get_ldap_settings(cls, cache=False):
229 def get_ldap_settings(cls, cache=False):
230 ret = cls.query()\
230 ret = cls.query()\
231 .filter(cls.app_settings_name.startswith('ldap_')).all()
231 .filter(cls.app_settings_name.startswith('ldap_')).all()
232 fd = {}
232 fd = {}
233 for row in ret:
233 for row in ret:
234 fd.update({row.app_settings_name: row.app_settings_value})
234 fd.update({row.app_settings_name: row.app_settings_value})
235
235
236 return fd
236 return fd
237
237
238 @classmethod
238 @classmethod
239 def get_default_repo_settings(cls, cache=False, strip_prefix=False):
239 def get_default_repo_settings(cls, cache=False, strip_prefix=False):
240 ret = cls.query()\
240 ret = cls.query()\
241 .filter(cls.app_settings_name.startswith('default_')).all()
241 .filter(cls.app_settings_name.startswith('default_')).all()
242 fd = {}
242 fd = {}
243 for row in ret:
243 for row in ret:
244 key = row.app_settings_name
244 key = row.app_settings_name
245 if strip_prefix:
245 if strip_prefix:
246 key = remove_prefix(key, prefix='default_')
246 key = remove_prefix(key, prefix='default_')
247 fd.update({key: row.app_settings_value})
247 fd.update({key: row.app_settings_value})
248
248
249 return fd
249 return fd
250
250
251
251
252 class RhodeCodeUi(Base, BaseModel):
252 class RhodeCodeUi(Base, BaseModel):
253 __tablename__ = 'rhodecode_ui'
253 __tablename__ = 'rhodecode_ui'
254 __table_args__ = (
254 __table_args__ = (
255 UniqueConstraint('ui_key'),
255 UniqueConstraint('ui_key'),
256 {'extend_existing': True, 'mysql_engine': 'InnoDB',
256 {'extend_existing': True, 'mysql_engine': 'InnoDB',
257 'mysql_charset': 'utf8'}
257 'mysql_charset': 'utf8'}
258 )
258 )
259
259
260 HOOK_UPDATE = 'changegroup.update'
260 HOOK_UPDATE = 'changegroup.update'
261 HOOK_REPO_SIZE = 'changegroup.repo_size'
261 HOOK_REPO_SIZE = 'changegroup.repo_size'
262 HOOK_PUSH = 'changegroup.push_logger'
262 HOOK_PUSH = 'changegroup.push_logger'
263 HOOK_PRE_PUSH = 'prechangegroup.pre_push'
263 HOOK_PRE_PUSH = 'prechangegroup.pre_push'
264 HOOK_PULL = 'outgoing.pull_logger'
264 HOOK_PULL = 'outgoing.pull_logger'
265 HOOK_PRE_PULL = 'preoutgoing.pre_pull'
265 HOOK_PRE_PULL = 'preoutgoing.pre_pull'
266
266
267 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
267 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
268 ui_section = Column("ui_section", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
268 ui_section = Column("ui_section", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
269 ui_key = Column("ui_key", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
269 ui_key = Column("ui_key", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
270 ui_value = Column("ui_value", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
270 ui_value = Column("ui_value", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
271 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
271 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
272
272
273 @classmethod
273 @classmethod
274 def get_by_key(cls, key):
274 def get_by_key(cls, key):
275 return cls.query().filter(cls.ui_key == key).scalar()
275 return cls.query().filter(cls.ui_key == key).scalar()
276
276
277 @classmethod
277 @classmethod
278 def get_builtin_hooks(cls):
278 def get_builtin_hooks(cls):
279 q = cls.query()
279 q = cls.query()
280 q = q.filter(cls.ui_key.in_([cls.HOOK_UPDATE, cls.HOOK_REPO_SIZE,
280 q = q.filter(cls.ui_key.in_([cls.HOOK_UPDATE, cls.HOOK_REPO_SIZE,
281 cls.HOOK_PUSH, cls.HOOK_PRE_PUSH,
281 cls.HOOK_PUSH, cls.HOOK_PRE_PUSH,
282 cls.HOOK_PULL, cls.HOOK_PRE_PULL]))
282 cls.HOOK_PULL, cls.HOOK_PRE_PULL]))
283 return q.all()
283 return q.all()
284
284
285 @classmethod
285 @classmethod
286 def get_custom_hooks(cls):
286 def get_custom_hooks(cls):
287 q = cls.query()
287 q = cls.query()
288 q = q.filter(~cls.ui_key.in_([cls.HOOK_UPDATE, cls.HOOK_REPO_SIZE,
288 q = q.filter(~cls.ui_key.in_([cls.HOOK_UPDATE, cls.HOOK_REPO_SIZE,
289 cls.HOOK_PUSH, cls.HOOK_PRE_PUSH,
289 cls.HOOK_PUSH, cls.HOOK_PRE_PUSH,
290 cls.HOOK_PULL, cls.HOOK_PRE_PULL]))
290 cls.HOOK_PULL, cls.HOOK_PRE_PULL]))
291 q = q.filter(cls.ui_section == 'hooks')
291 q = q.filter(cls.ui_section == 'hooks')
292 return q.all()
292 return q.all()
293
293
294 @classmethod
294 @classmethod
295 def get_repos_location(cls):
295 def get_repos_location(cls):
296 return cls.get_by_key('/').ui_value
296 return cls.get_by_key('/').ui_value
297
297
298 @classmethod
298 @classmethod
299 def create_or_update_hook(cls, key, val):
299 def create_or_update_hook(cls, key, val):
300 new_ui = cls.get_by_key(key) or cls()
300 new_ui = cls.get_by_key(key) or cls()
301 new_ui.ui_section = 'hooks'
301 new_ui.ui_section = 'hooks'
302 new_ui.ui_active = True
302 new_ui.ui_active = True
303 new_ui.ui_key = key
303 new_ui.ui_key = key
304 new_ui.ui_value = val
304 new_ui.ui_value = val
305
305
306 Session().add(new_ui)
306 Session().add(new_ui)
307
307
308 def __repr__(self):
308 def __repr__(self):
309 return '<DB:%s[%s:%s]>' % (self.__class__.__name__, self.ui_key,
309 return '<DB:%s[%s:%s]>' % (self.__class__.__name__, self.ui_key,
310 self.ui_value)
310 self.ui_value)
311
311
312
312
313 class User(Base, BaseModel):
313 class User(Base, BaseModel):
314 __tablename__ = 'users'
314 __tablename__ = 'users'
315 __table_args__ = (
315 __table_args__ = (
316 UniqueConstraint('username'), UniqueConstraint('email'),
316 UniqueConstraint('username'), UniqueConstraint('email'),
317 Index('u_username_idx', 'username'),
317 Index('u_username_idx', 'username'),
318 Index('u_email_idx', 'email'),
318 Index('u_email_idx', 'email'),
319 {'extend_existing': True, 'mysql_engine': 'InnoDB',
319 {'extend_existing': True, 'mysql_engine': 'InnoDB',
320 'mysql_charset': 'utf8'}
320 'mysql_charset': 'utf8'}
321 )
321 )
322 DEFAULT_USER = 'default'
322 DEFAULT_USER = 'default'
323
323
324 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
324 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
325 username = Column("username", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
325 username = Column("username", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
326 password = Column("password", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
326 password = Column("password", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
327 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
327 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
328 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
328 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
329 name = Column("firstname", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
329 name = Column("firstname", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
330 lastname = Column("lastname", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
330 lastname = Column("lastname", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
331 _email = Column("email", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
331 _email = Column("email", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
332 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
332 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
333 ldap_dn = Column("ldap_dn", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
333 ldap_dn = Column("ldap_dn", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
334 api_key = Column("api_key", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
334 api_key = Column("api_key", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
335 inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
335 inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
336
336
337 user_log = relationship('UserLog')
337 user_log = relationship('UserLog')
338 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
338 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
339
339
340 repositories = relationship('Repository')
340 repositories = relationship('Repository')
341 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
341 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
342 followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all')
342 followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all')
343
343
344 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
344 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
345 repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all')
345 repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all')
346
346
347 group_member = relationship('UserGroupMember', cascade='all')
347 group_member = relationship('UserGroupMember', cascade='all')
348
348
349 notifications = relationship('UserNotification', cascade='all')
349 notifications = relationship('UserNotification', cascade='all')
350 # notifications assigned to this user
350 # notifications assigned to this user
351 user_created_notifications = relationship('Notification', cascade='all')
351 user_created_notifications = relationship('Notification', cascade='all')
352 # comments created by this user
352 # comments created by this user
353 user_comments = relationship('ChangesetComment', cascade='all')
353 user_comments = relationship('ChangesetComment', cascade='all')
354 #extra emails for this user
354 #extra emails for this user
355 user_emails = relationship('UserEmailMap', cascade='all')
355 user_emails = relationship('UserEmailMap', cascade='all')
356
356
357 @hybrid_property
357 @hybrid_property
358 def email(self):
358 def email(self):
359 return self._email
359 return self._email
360
360
361 @email.setter
361 @email.setter
362 def email(self, val):
362 def email(self, val):
363 self._email = val.lower() if val else None
363 self._email = val.lower() if val else None
364
364
365 @property
365 @property
366 def firstname(self):
366 def firstname(self):
367 # alias for future
367 # alias for future
368 return self.name
368 return self.name
369
369
370 @property
370 @property
371 def emails(self):
371 def emails(self):
372 other = UserEmailMap.query().filter(UserEmailMap.user==self).all()
372 other = UserEmailMap.query().filter(UserEmailMap.user==self).all()
373 return [self.email] + [x.email for x in other]
373 return [self.email] + [x.email for x in other]
374
374
375 @property
375 @property
376 def ip_addresses(self):
376 def ip_addresses(self):
377 ret = UserIpMap.query().filter(UserIpMap.user == self).all()
377 ret = UserIpMap.query().filter(UserIpMap.user == self).all()
378 return [x.ip_addr for x in ret]
378 return [x.ip_addr for x in ret]
379
379
380 @property
380 @property
381 def username_and_name(self):
381 def username_and_name(self):
382 return '%s (%s %s)' % (self.username, self.firstname, self.lastname)
382 return '%s (%s %s)' % (self.username, self.firstname, self.lastname)
383
383
384 @property
384 @property
385 def full_name(self):
385 def full_name(self):
386 return '%s %s' % (self.firstname, self.lastname)
386 return '%s %s' % (self.firstname, self.lastname)
387
387
388 @property
388 @property
389 def full_name_or_username(self):
389 def full_name_or_username(self):
390 return ('%s %s' % (self.firstname, self.lastname)
390 return ('%s %s' % (self.firstname, self.lastname)
391 if (self.firstname and self.lastname) else self.username)
391 if (self.firstname and self.lastname) else self.username)
392
392
393 @property
393 @property
394 def full_contact(self):
394 def full_contact(self):
395 return '%s %s <%s>' % (self.firstname, self.lastname, self.email)
395 return '%s %s <%s>' % (self.firstname, self.lastname, self.email)
396
396
397 @property
397 @property
398 def short_contact(self):
398 def short_contact(self):
399 return '%s %s' % (self.firstname, self.lastname)
399 return '%s %s' % (self.firstname, self.lastname)
400
400
401 @property
401 @property
402 def is_admin(self):
402 def is_admin(self):
403 return self.admin
403 return self.admin
404
404
405 @property
405 @property
406 def AuthUser(self):
406 def AuthUser(self):
407 """
407 """
408 Returns instance of AuthUser for this user
408 Returns instance of AuthUser for this user
409 """
409 """
410 from rhodecode.lib.auth import AuthUser
410 from rhodecode.lib.auth import AuthUser
411 return AuthUser(user_id=self.user_id, api_key=self.api_key,
411 return AuthUser(user_id=self.user_id, api_key=self.api_key,
412 username=self.username)
412 username=self.username)
413
413
414 def __unicode__(self):
414 def __unicode__(self):
415 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
415 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
416 self.user_id, self.username)
416 self.user_id, self.username)
417
417
418 @classmethod
418 @classmethod
419 def get_by_username(cls, username, case_insensitive=False, cache=False):
419 def get_by_username(cls, username, case_insensitive=False, cache=False):
420 if case_insensitive:
420 if case_insensitive:
421 q = cls.query().filter(cls.username.ilike(username))
421 q = cls.query().filter(cls.username.ilike(username))
422 else:
422 else:
423 q = cls.query().filter(cls.username == username)
423 q = cls.query().filter(cls.username == username)
424
424
425 if cache:
425 if cache:
426 q = q.options(FromCache(
426 q = q.options(FromCache(
427 "sql_cache_short",
427 "sql_cache_short",
428 "get_user_%s" % _hash_key(username)
428 "get_user_%s" % _hash_key(username)
429 )
429 )
430 )
430 )
431 return q.scalar()
431 return q.scalar()
432
432
433 @classmethod
433 @classmethod
434 def get_by_api_key(cls, api_key, cache=False):
434 def get_by_api_key(cls, api_key, cache=False):
435 q = cls.query().filter(cls.api_key == api_key)
435 q = cls.query().filter(cls.api_key == api_key)
436
436
437 if cache:
437 if cache:
438 q = q.options(FromCache("sql_cache_short",
438 q = q.options(FromCache("sql_cache_short",
439 "get_api_key_%s" % api_key))
439 "get_api_key_%s" % api_key))
440 return q.scalar()
440 return q.scalar()
441
441
442 @classmethod
442 @classmethod
443 def get_by_email(cls, email, case_insensitive=False, cache=False):
443 def get_by_email(cls, email, case_insensitive=False, cache=False):
444 if case_insensitive:
444 if case_insensitive:
445 q = cls.query().filter(cls.email.ilike(email))
445 q = cls.query().filter(cls.email.ilike(email))
446 else:
446 else:
447 q = cls.query().filter(cls.email == email)
447 q = cls.query().filter(cls.email == email)
448
448
449 if cache:
449 if cache:
450 q = q.options(FromCache("sql_cache_short",
450 q = q.options(FromCache("sql_cache_short",
451 "get_email_key_%s" % email))
451 "get_email_key_%s" % email))
452
452
453 ret = q.scalar()
453 ret = q.scalar()
454 if ret is None:
454 if ret is None:
455 q = UserEmailMap.query()
455 q = UserEmailMap.query()
456 # try fetching in alternate email map
456 # try fetching in alternate email map
457 if case_insensitive:
457 if case_insensitive:
458 q = q.filter(UserEmailMap.email.ilike(email))
458 q = q.filter(UserEmailMap.email.ilike(email))
459 else:
459 else:
460 q = q.filter(UserEmailMap.email == email)
460 q = q.filter(UserEmailMap.email == email)
461 q = q.options(joinedload(UserEmailMap.user))
461 q = q.options(joinedload(UserEmailMap.user))
462 if cache:
462 if cache:
463 q = q.options(FromCache("sql_cache_short",
463 q = q.options(FromCache("sql_cache_short",
464 "get_email_map_key_%s" % email))
464 "get_email_map_key_%s" % email))
465 ret = getattr(q.scalar(), 'user', None)
465 ret = getattr(q.scalar(), 'user', None)
466
466
467 return ret
467 return ret
468
468
469 @classmethod
469 @classmethod
470 def get_from_cs_author(cls, author):
470 def get_from_cs_author(cls, author):
471 """
471 """
472 Tries to get User objects out of commit author string
472 Tries to get User objects out of commit author string
473
473
474 :param author:
474 :param author:
475 """
475 """
476 from rhodecode.lib.helpers import email, author_name
476 from rhodecode.lib.helpers import email, author_name
477 # Valid email in the attribute passed, see if they're in the system
477 # Valid email in the attribute passed, see if they're in the system
478 _email = email(author)
478 _email = email(author)
479 if _email:
479 if _email:
480 user = cls.get_by_email(_email, case_insensitive=True)
480 user = cls.get_by_email(_email, case_insensitive=True)
481 if user:
481 if user:
482 return user
482 return user
483 # Maybe we can match by username?
483 # Maybe we can match by username?
484 _author = author_name(author)
484 _author = author_name(author)
485 user = cls.get_by_username(_author, case_insensitive=True)
485 user = cls.get_by_username(_author, case_insensitive=True)
486 if user:
486 if user:
487 return user
487 return user
488
488
489 def update_lastlogin(self):
489 def update_lastlogin(self):
490 """Update user lastlogin"""
490 """Update user lastlogin"""
491 self.last_login = datetime.datetime.now()
491 self.last_login = datetime.datetime.now()
492 Session().add(self)
492 Session().add(self)
493 log.debug('updated user %s lastlogin' % self.username)
493 log.debug('updated user %s lastlogin' % self.username)
494
494
495 @classmethod
495 @classmethod
496 def get_first_admin(cls):
496 def get_first_admin(cls):
497 user = User.query().filter(User.admin == True).first()
497 user = User.query().filter(User.admin == True).first()
498 if user is None:
498 if user is None:
499 raise Exception('Missing administrative account!')
499 raise Exception('Missing administrative account!')
500 return user
500 return user
501
501
502 @classmethod
502 @classmethod
503 def get_default_user(cls, cache=False):
503 def get_default_user(cls, cache=False):
504 user = User.get_by_username(User.DEFAULT_USER, cache=cache)
504 user = User.get_by_username(User.DEFAULT_USER, cache=cache)
505 if user is None:
505 if user is None:
506 raise Exception('Missing default account!')
506 raise Exception('Missing default account!')
507 return user
507 return user
508
508
509 def get_api_data(self):
509 def get_api_data(self):
510 """
510 """
511 Common function for generating user related data for API
511 Common function for generating user related data for API
512 """
512 """
513 user = self
513 user = self
514 data = dict(
514 data = dict(
515 user_id=user.user_id,
515 user_id=user.user_id,
516 username=user.username,
516 username=user.username,
517 firstname=user.name,
517 firstname=user.name,
518 lastname=user.lastname,
518 lastname=user.lastname,
519 email=user.email,
519 email=user.email,
520 emails=user.emails,
520 emails=user.emails,
521 api_key=user.api_key,
521 api_key=user.api_key,
522 active=user.active,
522 active=user.active,
523 admin=user.admin,
523 admin=user.admin,
524 ldap_dn=user.ldap_dn,
524 ldap_dn=user.ldap_dn,
525 last_login=user.last_login,
525 last_login=user.last_login,
526 ip_addresses=user.ip_addresses
526 ip_addresses=user.ip_addresses
527 )
527 )
528 return data
528 return data
529
529
530 def __json__(self):
530 def __json__(self):
531 data = dict(
531 data = dict(
532 full_name=self.full_name,
532 full_name=self.full_name,
533 full_name_or_username=self.full_name_or_username,
533 full_name_or_username=self.full_name_or_username,
534 short_contact=self.short_contact,
534 short_contact=self.short_contact,
535 full_contact=self.full_contact
535 full_contact=self.full_contact
536 )
536 )
537 data.update(self.get_api_data())
537 data.update(self.get_api_data())
538 return data
538 return data
539
539
540
540
541 class UserEmailMap(Base, BaseModel):
541 class UserEmailMap(Base, BaseModel):
542 __tablename__ = 'user_email_map'
542 __tablename__ = 'user_email_map'
543 __table_args__ = (
543 __table_args__ = (
544 Index('uem_email_idx', 'email'),
544 Index('uem_email_idx', 'email'),
545 UniqueConstraint('email'),
545 UniqueConstraint('email'),
546 {'extend_existing': True, 'mysql_engine': 'InnoDB',
546 {'extend_existing': True, 'mysql_engine': 'InnoDB',
547 'mysql_charset': 'utf8'}
547 'mysql_charset': 'utf8'}
548 )
548 )
549 __mapper_args__ = {}
549 __mapper_args__ = {}
550
550
551 email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
551 email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
552 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
552 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
553 _email = Column("email", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
553 _email = Column("email", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
554 user = relationship('User', lazy='joined')
554 user = relationship('User', lazy='joined')
555
555
556 @validates('_email')
556 @validates('_email')
557 def validate_email(self, key, email):
557 def validate_email(self, key, email):
558 # check if this email is not main one
558 # check if this email is not main one
559 main_email = Session().query(User).filter(User.email == email).scalar()
559 main_email = Session().query(User).filter(User.email == email).scalar()
560 if main_email is not None:
560 if main_email is not None:
561 raise AttributeError('email %s is present is user table' % email)
561 raise AttributeError('email %s is present is user table' % email)
562 return email
562 return email
563
563
564 @hybrid_property
564 @hybrid_property
565 def email(self):
565 def email(self):
566 return self._email
566 return self._email
567
567
568 @email.setter
568 @email.setter
569 def email(self, val):
569 def email(self, val):
570 self._email = val.lower() if val else None
570 self._email = val.lower() if val else None
571
571
572
572
573 class UserIpMap(Base, BaseModel):
573 class UserIpMap(Base, BaseModel):
574 __tablename__ = 'user_ip_map'
574 __tablename__ = 'user_ip_map'
575 __table_args__ = (
575 __table_args__ = (
576 UniqueConstraint('user_id', 'ip_addr'),
576 UniqueConstraint('user_id', 'ip_addr'),
577 {'extend_existing': True, 'mysql_engine': 'InnoDB',
577 {'extend_existing': True, 'mysql_engine': 'InnoDB',
578 'mysql_charset': 'utf8'}
578 'mysql_charset': 'utf8'}
579 )
579 )
580 __mapper_args__ = {}
580 __mapper_args__ = {}
581
581
582 ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
582 ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
583 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
583 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
584 ip_addr = Column("ip_addr", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
584 ip_addr = Column("ip_addr", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
585 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
585 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
586 user = relationship('User', lazy='joined')
586 user = relationship('User', lazy='joined')
587
587
588 @classmethod
588 @classmethod
589 def _get_ip_range(cls, ip_addr):
589 def _get_ip_range(cls, ip_addr):
590 from rhodecode.lib import ipaddr
590 from rhodecode.lib import ipaddr
591 net = ipaddr.IPNetwork(address=ip_addr)
591 net = ipaddr.IPNetwork(address=ip_addr)
592 return [str(net.network), str(net.broadcast)]
592 return [str(net.network), str(net.broadcast)]
593
593
594 def __json__(self):
594 def __json__(self):
595 return dict(
595 return dict(
596 ip_addr=self.ip_addr,
596 ip_addr=self.ip_addr,
597 ip_range=self._get_ip_range(self.ip_addr)
597 ip_range=self._get_ip_range(self.ip_addr)
598 )
598 )
599
599
600
600
601 class UserLog(Base, BaseModel):
601 class UserLog(Base, BaseModel):
602 __tablename__ = 'user_logs'
602 __tablename__ = 'user_logs'
603 __table_args__ = (
603 __table_args__ = (
604 {'extend_existing': True, 'mysql_engine': 'InnoDB',
604 {'extend_existing': True, 'mysql_engine': 'InnoDB',
605 'mysql_charset': 'utf8'},
605 'mysql_charset': 'utf8'},
606 )
606 )
607 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
607 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
608 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
608 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
609 username = Column("username", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
609 username = Column("username", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
610 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
610 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
611 repository_name = Column("repository_name", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
611 repository_name = Column("repository_name", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
612 user_ip = Column("user_ip", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
612 user_ip = Column("user_ip", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
613 action = Column("action", UnicodeText(1200000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
613 action = Column("action", UnicodeText(1200000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
614 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
614 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
615
615
616 def __unicode__(self):
616 def __unicode__(self):
617 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
617 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
618 self.repository_name,
618 self.repository_name,
619 self.action)
619 self.action)
620
620
621 @property
621 @property
622 def action_as_day(self):
622 def action_as_day(self):
623 return datetime.date(*self.action_date.timetuple()[:3])
623 return datetime.date(*self.action_date.timetuple()[:3])
624
624
625 user = relationship('User')
625 user = relationship('User')
626 repository = relationship('Repository', cascade='')
626 repository = relationship('Repository', cascade='')
627
627
628
628
629 class UserGroup(Base, BaseModel):
629 class UserGroup(Base, BaseModel):
630 __tablename__ = 'users_groups'
630 __tablename__ = 'users_groups'
631 __table_args__ = (
631 __table_args__ = (
632 {'extend_existing': True, 'mysql_engine': 'InnoDB',
632 {'extend_existing': True, 'mysql_engine': 'InnoDB',
633 'mysql_charset': 'utf8'},
633 'mysql_charset': 'utf8'},
634 )
634 )
635
635
636 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
636 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
637 users_group_name = Column("users_group_name", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
637 users_group_name = Column("users_group_name", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
638 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
638 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
639 inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
639 inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
640 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
640 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
641
641
642 members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
642 members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
643 users_group_to_perm = relationship('UserGroupToPerm', cascade='all')
643 users_group_to_perm = relationship('UserGroupToPerm', cascade='all')
644 users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
644 users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
645 users_group_repo_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
645 users_group_repo_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
646 user_user_group_to_perm = relationship('UserUserGroupToPerm ', cascade='all')
646 user_user_group_to_perm = relationship('UserUserGroupToPerm ', cascade='all')
647 user_group_user_group_to_perm = relationship('UserGroupUserGroupToPerm ', primaryjoin="UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id", cascade='all')
647 user_group_user_group_to_perm = relationship('UserGroupUserGroupToPerm ', primaryjoin="UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id", cascade='all')
648
648
649 user = relationship('User')
649 user = relationship('User')
650
650
651 def __unicode__(self):
651 def __unicode__(self):
652 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
652 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
653 self.users_group_id,
653 self.users_group_id,
654 self.users_group_name)
654 self.users_group_name)
655
655
656 @classmethod
656 @classmethod
657 def get_by_group_name(cls, group_name, cache=False,
657 def get_by_group_name(cls, group_name, cache=False,
658 case_insensitive=False):
658 case_insensitive=False):
659 if case_insensitive:
659 if case_insensitive:
660 q = cls.query().filter(cls.users_group_name.ilike(group_name))
660 q = cls.query().filter(cls.users_group_name.ilike(group_name))
661 else:
661 else:
662 q = cls.query().filter(cls.users_group_name == group_name)
662 q = cls.query().filter(cls.users_group_name == group_name)
663 if cache:
663 if cache:
664 q = q.options(FromCache(
664 q = q.options(FromCache(
665 "sql_cache_short",
665 "sql_cache_short",
666 "get_user_%s" % _hash_key(group_name)
666 "get_user_%s" % _hash_key(group_name)
667 )
667 )
668 )
668 )
669 return q.scalar()
669 return q.scalar()
670
670
671 @classmethod
671 @classmethod
672 def get(cls, users_group_id, cache=False):
672 def get(cls, users_group_id, cache=False):
673 users_group = cls.query()
673 users_group = cls.query()
674 if cache:
674 if cache:
675 users_group = users_group.options(FromCache("sql_cache_short",
675 users_group = users_group.options(FromCache("sql_cache_short",
676 "get_users_group_%s" % users_group_id))
676 "get_users_group_%s" % users_group_id))
677 return users_group.get(users_group_id)
677 return users_group.get(users_group_id)
678
678
679 def get_api_data(self):
679 def get_api_data(self):
680 users_group = self
680 users_group = self
681
681
682 data = dict(
682 data = dict(
683 users_group_id=users_group.users_group_id,
683 users_group_id=users_group.users_group_id,
684 group_name=users_group.users_group_name,
684 group_name=users_group.users_group_name,
685 active=users_group.users_group_active,
685 active=users_group.users_group_active,
686 )
686 )
687
687
688 return data
688 return data
689
689
690
690
691 class UserGroupMember(Base, BaseModel):
691 class UserGroupMember(Base, BaseModel):
692 __tablename__ = 'users_groups_members'
692 __tablename__ = 'users_groups_members'
693 __table_args__ = (
693 __table_args__ = (
694 {'extend_existing': True, 'mysql_engine': 'InnoDB',
694 {'extend_existing': True, 'mysql_engine': 'InnoDB',
695 'mysql_charset': 'utf8'},
695 'mysql_charset': 'utf8'},
696 )
696 )
697
697
698 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
698 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
699 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
699 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
700 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
700 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
701
701
702 user = relationship('User', lazy='joined')
702 user = relationship('User', lazy='joined')
703 users_group = relationship('UserGroup')
703 users_group = relationship('UserGroup')
704
704
705 def __init__(self, gr_id='', u_id=''):
705 def __init__(self, gr_id='', u_id=''):
706 self.users_group_id = gr_id
706 self.users_group_id = gr_id
707 self.user_id = u_id
707 self.user_id = u_id
708
708
709
709
710 class RepositoryField(Base, BaseModel):
710 class RepositoryField(Base, BaseModel):
711 __tablename__ = 'repositories_fields'
711 __tablename__ = 'repositories_fields'
712 __table_args__ = (
712 __table_args__ = (
713 UniqueConstraint('repository_id', 'field_key'), # no-multi field
713 UniqueConstraint('repository_id', 'field_key'), # no-multi field
714 {'extend_existing': True, 'mysql_engine': 'InnoDB',
714 {'extend_existing': True, 'mysql_engine': 'InnoDB',
715 'mysql_charset': 'utf8'},
715 'mysql_charset': 'utf8'},
716 )
716 )
717 PREFIX = 'ex_' # prefix used in form to not conflict with already existing fields
717 PREFIX = 'ex_' # prefix used in form to not conflict with already existing fields
718
718
719 repo_field_id = Column("repo_field_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
719 repo_field_id = Column("repo_field_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
720 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
720 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
721 field_key = Column("field_key", String(250, convert_unicode=False, assert_unicode=None))
721 field_key = Column("field_key", String(250, convert_unicode=False, assert_unicode=None))
722 field_label = Column("field_label", String(1024, convert_unicode=False, assert_unicode=None), nullable=False)
722 field_label = Column("field_label", String(1024, convert_unicode=False, assert_unicode=None), nullable=False)
723 field_value = Column("field_value", String(10000, convert_unicode=False, assert_unicode=None), nullable=False)
723 field_value = Column("field_value", String(10000, convert_unicode=False, assert_unicode=None), nullable=False)
724 field_desc = Column("field_desc", String(1024, convert_unicode=False, assert_unicode=None), nullable=False)
724 field_desc = Column("field_desc", String(1024, convert_unicode=False, assert_unicode=None), nullable=False)
725 field_type = Column("field_type", String(256), nullable=False, unique=None)
725 field_type = Column("field_type", String(256), nullable=False, unique=None)
726 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
726 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
727
727
728 repository = relationship('Repository')
728 repository = relationship('Repository')
729
729
730 @property
730 @property
731 def field_key_prefixed(self):
731 def field_key_prefixed(self):
732 return 'ex_%s' % self.field_key
732 return 'ex_%s' % self.field_key
733
733
734 @classmethod
734 @classmethod
735 def un_prefix_key(cls, key):
735 def un_prefix_key(cls, key):
736 if key.startswith(cls.PREFIX):
736 if key.startswith(cls.PREFIX):
737 return key[len(cls.PREFIX):]
737 return key[len(cls.PREFIX):]
738 return key
738 return key
739
739
740 @classmethod
740 @classmethod
741 def get_by_key_name(cls, key, repo):
741 def get_by_key_name(cls, key, repo):
742 row = cls.query()\
742 row = cls.query()\
743 .filter(cls.repository == repo)\
743 .filter(cls.repository == repo)\
744 .filter(cls.field_key == key).scalar()
744 .filter(cls.field_key == key).scalar()
745 return row
745 return row
746
746
747
747
748 class Repository(Base, BaseModel):
748 class Repository(Base, BaseModel):
749 __tablename__ = 'repositories'
749 __tablename__ = 'repositories'
750 __table_args__ = (
750 __table_args__ = (
751 UniqueConstraint('repo_name'),
751 UniqueConstraint('repo_name'),
752 Index('r_repo_name_idx', 'repo_name'),
752 Index('r_repo_name_idx', 'repo_name'),
753 {'extend_existing': True, 'mysql_engine': 'InnoDB',
753 {'extend_existing': True, 'mysql_engine': 'InnoDB',
754 'mysql_charset': 'utf8'},
754 'mysql_charset': 'utf8'},
755 )
755 )
756
756
757 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
757 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
758 repo_name = Column("repo_name", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
758 repo_name = Column("repo_name", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
759 clone_uri = Column("clone_uri", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
759 clone_uri = Column("clone_uri", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
760 repo_type = Column("repo_type", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default=None)
760 repo_type = Column("repo_type", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default=None)
761 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
761 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
762 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
762 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
763 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
763 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
764 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
764 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
765 description = Column("description", String(10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
765 description = Column("description", String(10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
766 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
766 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
767 updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
767 updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
768 landing_rev = Column("landing_revision", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default=None)
768 landing_rev = Column("landing_revision", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default=None)
769 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
769 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
770 _locked = Column("locked", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
770 _locked = Column("locked", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
771 _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) #JSON data
771 _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) #JSON data
772
772
773 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
773 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
774 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
774 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
775
775
776 user = relationship('User')
776 user = relationship('User')
777 fork = relationship('Repository', remote_side=repo_id)
777 fork = relationship('Repository', remote_side=repo_id)
778 group = relationship('RepoGroup')
778 group = relationship('RepoGroup')
779 repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
779 repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
780 users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
780 users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
781 stats = relationship('Statistics', cascade='all', uselist=False)
781 stats = relationship('Statistics', cascade='all', uselist=False)
782
782
783 followers = relationship('UserFollowing',
783 followers = relationship('UserFollowing',
784 primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id',
784 primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id',
785 cascade='all')
785 cascade='all')
786 extra_fields = relationship('RepositoryField',
786 extra_fields = relationship('RepositoryField',
787 cascade="all, delete, delete-orphan")
787 cascade="all, delete, delete-orphan")
788
788
789 logs = relationship('UserLog')
789 logs = relationship('UserLog')
790 comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan")
790 comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan")
791
791
792 pull_requests_org = relationship('PullRequest',
792 pull_requests_org = relationship('PullRequest',
793 primaryjoin='PullRequest.org_repo_id==Repository.repo_id',
793 primaryjoin='PullRequest.org_repo_id==Repository.repo_id',
794 cascade="all, delete, delete-orphan")
794 cascade="all, delete, delete-orphan")
795
795
796 pull_requests_other = relationship('PullRequest',
796 pull_requests_other = relationship('PullRequest',
797 primaryjoin='PullRequest.other_repo_id==Repository.repo_id',
797 primaryjoin='PullRequest.other_repo_id==Repository.repo_id',
798 cascade="all, delete, delete-orphan")
798 cascade="all, delete, delete-orphan")
799
799
800 def __unicode__(self):
800 def __unicode__(self):
801 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id,
801 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id,
802 self.repo_name)
802 self.repo_name)
803
803
804 @hybrid_property
804 @hybrid_property
805 def locked(self):
805 def locked(self):
806 # always should return [user_id, timelocked]
806 # always should return [user_id, timelocked]
807 if self._locked:
807 if self._locked:
808 _lock_info = self._locked.split(':')
808 _lock_info = self._locked.split(':')
809 return int(_lock_info[0]), _lock_info[1]
809 return int(_lock_info[0]), _lock_info[1]
810 return [None, None]
810 return [None, None]
811
811
812 @locked.setter
812 @locked.setter
813 def locked(self, val):
813 def locked(self, val):
814 if val and isinstance(val, (list, tuple)):
814 if val and isinstance(val, (list, tuple)):
815 self._locked = ':'.join(map(str, val))
815 self._locked = ':'.join(map(str, val))
816 else:
816 else:
817 self._locked = None
817 self._locked = None
818
818
819 @hybrid_property
819 @hybrid_property
820 def changeset_cache(self):
820 def changeset_cache(self):
821 from rhodecode.lib.vcs.backends.base import EmptyChangeset
821 from rhodecode.lib.vcs.backends.base import EmptyChangeset
822 dummy = EmptyChangeset().__json__()
822 dummy = EmptyChangeset().__json__()
823 if not self._changeset_cache:
823 if not self._changeset_cache:
824 return dummy
824 return dummy
825 try:
825 try:
826 return json.loads(self._changeset_cache)
826 return json.loads(self._changeset_cache)
827 except TypeError:
827 except TypeError:
828 return dummy
828 return dummy
829
829
830 @changeset_cache.setter
830 @changeset_cache.setter
831 def changeset_cache(self, val):
831 def changeset_cache(self, val):
832 try:
832 try:
833 self._changeset_cache = json.dumps(val)
833 self._changeset_cache = json.dumps(val)
834 except Exception:
834 except Exception:
835 log.error(traceback.format_exc())
835 log.error(traceback.format_exc())
836
836
837 @classmethod
837 @classmethod
838 def url_sep(cls):
838 def url_sep(cls):
839 return URL_SEP
839 return URL_SEP
840
840
841 @classmethod
841 @classmethod
842 def normalize_repo_name(cls, repo_name):
842 def normalize_repo_name(cls, repo_name):
843 """
843 """
844 Normalizes os specific repo_name to the format internally stored inside
844 Normalizes os specific repo_name to the format internally stored inside
845 dabatabase using URL_SEP
845 dabatabase using URL_SEP
846
846
847 :param cls:
847 :param cls:
848 :param repo_name:
848 :param repo_name:
849 """
849 """
850 return cls.url_sep().join(repo_name.split(os.sep))
850 return cls.url_sep().join(repo_name.split(os.sep))
851
851
852 @classmethod
852 @classmethod
853 def get_by_repo_name(cls, repo_name):
853 def get_by_repo_name(cls, repo_name):
854 q = Session().query(cls).filter(cls.repo_name == repo_name)
854 q = Session().query(cls).filter(cls.repo_name == repo_name)
855 q = q.options(joinedload(Repository.fork))\
855 q = q.options(joinedload(Repository.fork))\
856 .options(joinedload(Repository.user))\
856 .options(joinedload(Repository.user))\
857 .options(joinedload(Repository.group))
857 .options(joinedload(Repository.group))
858 return q.scalar()
858 return q.scalar()
859
859
860 @classmethod
860 @classmethod
861 def get_by_full_path(cls, repo_full_path):
861 def get_by_full_path(cls, repo_full_path):
862 repo_name = repo_full_path.split(cls.base_path(), 1)[-1]
862 repo_name = repo_full_path.split(cls.base_path(), 1)[-1]
863 repo_name = cls.normalize_repo_name(repo_name)
863 repo_name = cls.normalize_repo_name(repo_name)
864 return cls.get_by_repo_name(repo_name.strip(URL_SEP))
864 return cls.get_by_repo_name(repo_name.strip(URL_SEP))
865
865
866 @classmethod
866 @classmethod
867 def get_repo_forks(cls, repo_id):
867 def get_repo_forks(cls, repo_id):
868 return cls.query().filter(Repository.fork_id == repo_id)
868 return cls.query().filter(Repository.fork_id == repo_id)
869
869
870 @classmethod
870 @classmethod
871 def base_path(cls):
871 def base_path(cls):
872 """
872 """
873 Returns base path when all repos are stored
873 Returns base path when all repos are stored
874
874
875 :param cls:
875 :param cls:
876 """
876 """
877 q = Session().query(RhodeCodeUi)\
877 q = Session().query(RhodeCodeUi)\
878 .filter(RhodeCodeUi.ui_key == cls.url_sep())
878 .filter(RhodeCodeUi.ui_key == cls.url_sep())
879 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
879 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
880 return q.one().ui_value
880 return q.one().ui_value
881
881
882 @property
882 @property
883 def forks(self):
883 def forks(self):
884 """
884 """
885 Return forks of this repo
885 Return forks of this repo
886 """
886 """
887 return Repository.get_repo_forks(self.repo_id)
887 return Repository.get_repo_forks(self.repo_id)
888
888
889 @property
889 @property
890 def parent(self):
890 def parent(self):
891 """
891 """
892 Returns fork parent
892 Returns fork parent
893 """
893 """
894 return self.fork
894 return self.fork
895
895
896 @property
896 @property
897 def just_name(self):
897 def just_name(self):
898 return self.repo_name.split(Repository.url_sep())[-1]
898 return self.repo_name.split(Repository.url_sep())[-1]
899
899
900 @property
900 @property
901 def groups_with_parents(self):
901 def groups_with_parents(self):
902 groups = []
902 groups = []
903 if self.group is None:
903 if self.group is None:
904 return groups
904 return groups
905
905
906 cur_gr = self.group
906 cur_gr = self.group
907 groups.insert(0, cur_gr)
907 groups.insert(0, cur_gr)
908 while 1:
908 while 1:
909 gr = getattr(cur_gr, 'parent_group', None)
909 gr = getattr(cur_gr, 'parent_group', None)
910 cur_gr = cur_gr.parent_group
910 cur_gr = cur_gr.parent_group
911 if gr is None:
911 if gr is None:
912 break
912 break
913 groups.insert(0, gr)
913 groups.insert(0, gr)
914
914
915 return groups
915 return groups
916
916
917 @property
917 @property
918 def groups_and_repo(self):
918 def groups_and_repo(self):
919 return self.groups_with_parents, self.just_name, self.repo_name
919 return self.groups_with_parents, self.just_name, self.repo_name
920
920
921 @LazyProperty
921 @LazyProperty
922 def repo_path(self):
922 def repo_path(self):
923 """
923 """
924 Returns base full path for that repository means where it actually
924 Returns base full path for that repository means where it actually
925 exists on a filesystem
925 exists on a filesystem
926 """
926 """
927 q = Session().query(RhodeCodeUi).filter(RhodeCodeUi.ui_key ==
927 q = Session().query(RhodeCodeUi).filter(RhodeCodeUi.ui_key ==
928 Repository.url_sep())
928 Repository.url_sep())
929 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
929 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
930 return q.one().ui_value
930 return q.one().ui_value
931
931
932 @property
932 @property
933 def repo_full_path(self):
933 def repo_full_path(self):
934 p = [self.repo_path]
934 p = [self.repo_path]
935 # we need to split the name by / since this is how we store the
935 # we need to split the name by / since this is how we store the
936 # names in the database, but that eventually needs to be converted
936 # names in the database, but that eventually needs to be converted
937 # into a valid system path
937 # into a valid system path
938 p += self.repo_name.split(Repository.url_sep())
938 p += self.repo_name.split(Repository.url_sep())
939 return os.path.join(*map(safe_unicode, p))
939 return os.path.join(*map(safe_unicode, p))
940
940
941 @property
941 @property
942 def cache_keys(self):
942 def cache_keys(self):
943 """
943 """
944 Returns associated cache keys for that repo
944 Returns associated cache keys for that repo
945 """
945 """
946 return CacheInvalidation.query()\
946 return CacheInvalidation.query()\
947 .filter(CacheInvalidation.cache_args == self.repo_name)\
947 .filter(CacheInvalidation.cache_args == self.repo_name)\
948 .order_by(CacheInvalidation.cache_key)\
948 .order_by(CacheInvalidation.cache_key)\
949 .all()
949 .all()
950
950
951 def get_new_name(self, repo_name):
951 def get_new_name(self, repo_name):
952 """
952 """
953 returns new full repository name based on assigned group and new new
953 returns new full repository name based on assigned group and new new
954
954
955 :param group_name:
955 :param group_name:
956 """
956 """
957 path_prefix = self.group.full_path_splitted if self.group else []
957 path_prefix = self.group.full_path_splitted if self.group else []
958 return Repository.url_sep().join(path_prefix + [repo_name])
958 return Repository.url_sep().join(path_prefix + [repo_name])
959
959
960 @property
960 @property
961 def _ui(self):
961 def _ui(self):
962 """
962 """
963 Creates an db based ui object for this repository
963 Creates an db based ui object for this repository
964 """
964 """
965 from rhodecode.lib.utils import make_ui
965 from rhodecode.lib.utils import make_ui
966 return make_ui('db', clear_session=False)
966 return make_ui('db', clear_session=False)
967
967
968 @classmethod
968 @classmethod
969 def is_valid(cls, repo_name):
969 def is_valid(cls, repo_name):
970 """
970 """
971 returns True if given repo name is a valid filesystem repository
971 returns True if given repo name is a valid filesystem repository
972
972
973 :param cls:
973 :param cls:
974 :param repo_name:
974 :param repo_name:
975 """
975 """
976 from rhodecode.lib.utils import is_valid_repo
976 from rhodecode.lib.utils import is_valid_repo
977
977
978 return is_valid_repo(repo_name, cls.base_path())
978 return is_valid_repo(repo_name, cls.base_path())
979
979
980 def get_api_data(self):
980 def get_api_data(self):
981 """
981 """
982 Common function for generating repo api data
982 Common function for generating repo api data
983
983
984 """
984 """
985 repo = self
985 repo = self
986 data = dict(
986 data = dict(
987 repo_id=repo.repo_id,
987 repo_id=repo.repo_id,
988 repo_name=repo.repo_name,
988 repo_name=repo.repo_name,
989 repo_type=repo.repo_type,
989 repo_type=repo.repo_type,
990 clone_uri=repo.clone_uri,
990 clone_uri=repo.clone_uri,
991 private=repo.private,
991 private=repo.private,
992 created_on=repo.created_on,
992 created_on=repo.created_on,
993 description=repo.description,
993 description=repo.description,
994 landing_rev=repo.landing_rev,
994 landing_rev=repo.landing_rev,
995 owner=repo.user.username,
995 owner=repo.user.username,
996 fork_of=repo.fork.repo_name if repo.fork else None,
996 fork_of=repo.fork.repo_name if repo.fork else None,
997 enable_statistics=repo.enable_statistics,
997 enable_statistics=repo.enable_statistics,
998 enable_locking=repo.enable_locking,
998 enable_locking=repo.enable_locking,
999 enable_downloads=repo.enable_downloads,
999 enable_downloads=repo.enable_downloads,
1000 last_changeset=repo.changeset_cache,
1000 last_changeset=repo.changeset_cache,
1001 locked_by=User.get(self.locked[0]).get_api_data() \
1001 locked_by=User.get(self.locked[0]).get_api_data() \
1002 if self.locked[0] else None,
1002 if self.locked[0] else None,
1003 locked_date=time_to_datetime(self.locked[1]) \
1003 locked_date=time_to_datetime(self.locked[1]) \
1004 if self.locked[1] else None
1004 if self.locked[1] else None
1005 )
1005 )
1006 rc_config = RhodeCodeSetting.get_app_settings()
1006 rc_config = RhodeCodeSetting.get_app_settings()
1007 repository_fields = str2bool(rc_config.get('rhodecode_repository_fields'))
1007 repository_fields = str2bool(rc_config.get('rhodecode_repository_fields'))
1008 if repository_fields:
1008 if repository_fields:
1009 for f in self.extra_fields:
1009 for f in self.extra_fields:
1010 data[f.field_key_prefixed] = f.field_value
1010 data[f.field_key_prefixed] = f.field_value
1011
1011
1012 return data
1012 return data
1013
1013
1014 @classmethod
1014 @classmethod
1015 def lock(cls, repo, user_id, lock_time=None):
1015 def lock(cls, repo, user_id, lock_time=None):
1016 if not lock_time:
1016 if not lock_time:
1017 lock_time = time.time()
1017 lock_time = time.time()
1018 repo.locked = [user_id, lock_time]
1018 repo.locked = [user_id, lock_time]
1019 Session().add(repo)
1019 Session().add(repo)
1020 Session().commit()
1020 Session().commit()
1021
1021
1022 @classmethod
1022 @classmethod
1023 def unlock(cls, repo):
1023 def unlock(cls, repo):
1024 repo.locked = None
1024 repo.locked = None
1025 Session().add(repo)
1025 Session().add(repo)
1026 Session().commit()
1026 Session().commit()
1027
1027
1028 @classmethod
1028 @classmethod
1029 def getlock(cls, repo):
1029 def getlock(cls, repo):
1030 return repo.locked
1030 return repo.locked
1031
1031
1032 @property
1032 @property
1033 def last_db_change(self):
1033 def last_db_change(self):
1034 return self.updated_on
1034 return self.updated_on
1035
1035
1036 def clone_url(self, **override):
1036 def clone_url(self, **override):
1037 from pylons import url
1037 from pylons import url
1038 from urlparse import urlparse
1038 from urlparse import urlparse
1039 import urllib
1039 import urllib
1040 parsed_url = urlparse(url('home', qualified=True))
1040 parsed_url = urlparse(url('home', qualified=True))
1041 default_clone_uri = '%(scheme)s://%(user)s%(pass)s%(netloc)s%(prefix)s%(path)s'
1041 default_clone_uri = '%(scheme)s://%(user)s%(pass)s%(netloc)s%(prefix)s%(path)s'
1042 decoded_path = safe_unicode(urllib.unquote(parsed_url.path))
1042 decoded_path = safe_unicode(urllib.unquote(parsed_url.path))
1043 args = {
1043 args = {
1044 'user': '',
1044 'user': '',
1045 'pass': '',
1045 'pass': '',
1046 'scheme': parsed_url.scheme,
1046 'scheme': parsed_url.scheme,
1047 'netloc': parsed_url.netloc,
1047 'netloc': parsed_url.netloc,
1048 'prefix': decoded_path,
1048 'prefix': decoded_path,
1049 'path': self.repo_name
1049 'path': self.repo_name
1050 }
1050 }
1051
1051
1052 args.update(override)
1052 args.update(override)
1053 return default_clone_uri % args
1053 return default_clone_uri % args
1054
1054
1055 #==========================================================================
1055 #==========================================================================
1056 # SCM PROPERTIES
1056 # SCM PROPERTIES
1057 #==========================================================================
1057 #==========================================================================
1058
1058
1059 def get_changeset(self, rev=None):
1059 def get_changeset(self, rev=None):
1060 return get_changeset_safe(self.scm_instance, rev)
1060 return get_changeset_safe(self.scm_instance, rev)
1061
1061
1062 def get_landing_changeset(self):
1062 def get_landing_changeset(self):
1063 """
1063 """
1064 Returns landing changeset, or if that doesn't exist returns the tip
1064 Returns landing changeset, or if that doesn't exist returns the tip
1065 """
1065 """
1066 cs = self.get_changeset(self.landing_rev) or self.get_changeset()
1066 cs = self.get_changeset(self.landing_rev) or self.get_changeset()
1067 return cs
1067 return cs
1068
1068
1069 def update_changeset_cache(self, cs_cache=None):
1069 def update_changeset_cache(self, cs_cache=None):
1070 """
1070 """
1071 Update cache of last changeset for repository, keys should be::
1071 Update cache of last changeset for repository, keys should be::
1072
1072
1073 short_id
1073 short_id
1074 raw_id
1074 raw_id
1075 revision
1075 revision
1076 message
1076 message
1077 date
1077 date
1078 author
1078 author
1079
1079
1080 :param cs_cache:
1080 :param cs_cache:
1081 """
1081 """
1082 from rhodecode.lib.vcs.backends.base import BaseChangeset
1082 from rhodecode.lib.vcs.backends.base import BaseChangeset
1083 if cs_cache is None:
1083 if cs_cache is None:
1084 cs_cache = EmptyChangeset()
1084 cs_cache = EmptyChangeset()
1085 # use no-cache version here
1085 # use no-cache version here
1086 scm_repo = self.scm_instance_no_cache()
1086 scm_repo = self.scm_instance_no_cache()
1087 if scm_repo:
1087 if scm_repo:
1088 cs_cache = scm_repo.get_changeset()
1088 cs_cache = scm_repo.get_changeset()
1089
1089
1090 if isinstance(cs_cache, BaseChangeset):
1090 if isinstance(cs_cache, BaseChangeset):
1091 cs_cache = cs_cache.__json__()
1091 cs_cache = cs_cache.__json__()
1092
1092
1093 if (cs_cache != self.changeset_cache or not self.changeset_cache):
1093 if (cs_cache != self.changeset_cache or not self.changeset_cache):
1094 _default = datetime.datetime.fromtimestamp(0)
1094 _default = datetime.datetime.fromtimestamp(0)
1095 last_change = cs_cache.get('date') or _default
1095 last_change = cs_cache.get('date') or _default
1096 log.debug('updated repo %s with new cs cache %s'
1096 log.debug('updated repo %s with new cs cache %s'
1097 % (self.repo_name, cs_cache))
1097 % (self.repo_name, cs_cache))
1098 self.updated_on = last_change
1098 self.updated_on = last_change
1099 self.changeset_cache = cs_cache
1099 self.changeset_cache = cs_cache
1100 Session().add(self)
1100 Session().add(self)
1101 Session().commit()
1101 Session().commit()
1102 else:
1102 else:
1103 log.debug('Skipping repo:%s already with latest changes'
1103 log.debug('Skipping repo:%s already with latest changes'
1104 % self.repo_name)
1104 % self.repo_name)
1105
1105
1106 @property
1106 @property
1107 def tip(self):
1107 def tip(self):
1108 return self.get_changeset('tip')
1108 return self.get_changeset('tip')
1109
1109
1110 @property
1110 @property
1111 def author(self):
1111 def author(self):
1112 return self.tip.author
1112 return self.tip.author
1113
1113
1114 @property
1114 @property
1115 def last_change(self):
1115 def last_change(self):
1116 return self.scm_instance.last_change
1116 return self.scm_instance.last_change
1117
1117
1118 def get_comments(self, revisions=None):
1118 def get_comments(self, revisions=None):
1119 """
1119 """
1120 Returns comments for this repository grouped by revisions
1120 Returns comments for this repository grouped by revisions
1121
1121
1122 :param revisions: filter query by revisions only
1122 :param revisions: filter query by revisions only
1123 """
1123 """
1124 cmts = ChangesetComment.query()\
1124 cmts = ChangesetComment.query()\
1125 .filter(ChangesetComment.repo == self)
1125 .filter(ChangesetComment.repo == self)
1126 if revisions:
1126 if revisions:
1127 cmts = cmts.filter(ChangesetComment.revision.in_(revisions))
1127 cmts = cmts.filter(ChangesetComment.revision.in_(revisions))
1128 grouped = collections.defaultdict(list)
1128 grouped = collections.defaultdict(list)
1129 for cmt in cmts.all():
1129 for cmt in cmts.all():
1130 grouped[cmt.revision].append(cmt)
1130 grouped[cmt.revision].append(cmt)
1131 return grouped
1131 return grouped
1132
1132
1133 def statuses(self, revisions=None):
1133 def statuses(self, revisions=None):
1134 """
1134 """
1135 Returns statuses for this repository
1135 Returns statuses for this repository
1136
1136
1137 :param revisions: list of revisions to get statuses for
1137 :param revisions: list of revisions to get statuses for
1138 """
1138 """
1139
1139
1140 statuses = ChangesetStatus.query()\
1140 statuses = ChangesetStatus.query()\
1141 .filter(ChangesetStatus.repo == self)\
1141 .filter(ChangesetStatus.repo == self)\
1142 .filter(ChangesetStatus.version == 0)
1142 .filter(ChangesetStatus.version == 0)
1143 if revisions:
1143 if revisions:
1144 statuses = statuses.filter(ChangesetStatus.revision.in_(revisions))
1144 statuses = statuses.filter(ChangesetStatus.revision.in_(revisions))
1145 grouped = {}
1145 grouped = {}
1146
1146
1147 #maybe we have open new pullrequest without a status ?
1147 #maybe we have open new pullrequest without a status ?
1148 stat = ChangesetStatus.STATUS_UNDER_REVIEW
1148 stat = ChangesetStatus.STATUS_UNDER_REVIEW
1149 status_lbl = ChangesetStatus.get_status_lbl(stat)
1149 status_lbl = ChangesetStatus.get_status_lbl(stat)
1150 for pr in PullRequest.query().filter(PullRequest.org_repo == self).all():
1150 for pr in PullRequest.query().filter(PullRequest.org_repo == self).all():
1151 for rev in pr.revisions:
1151 for rev in pr.revisions:
1152 pr_id = pr.pull_request_id
1152 pr_id = pr.pull_request_id
1153 pr_repo = pr.other_repo.repo_name
1153 pr_repo = pr.other_repo.repo_name
1154 grouped[rev] = [stat, status_lbl, pr_id, pr_repo]
1154 grouped[rev] = [stat, status_lbl, pr_id, pr_repo]
1155
1155
1156 for stat in statuses.all():
1156 for stat in statuses.all():
1157 pr_id = pr_repo = None
1157 pr_id = pr_repo = None
1158 if stat.pull_request:
1158 if stat.pull_request:
1159 pr_id = stat.pull_request.pull_request_id
1159 pr_id = stat.pull_request.pull_request_id
1160 pr_repo = stat.pull_request.other_repo.repo_name
1160 pr_repo = stat.pull_request.other_repo.repo_name
1161 grouped[stat.revision] = [str(stat.status), stat.status_lbl,
1161 grouped[stat.revision] = [str(stat.status), stat.status_lbl,
1162 pr_id, pr_repo]
1162 pr_id, pr_repo]
1163 return grouped
1163 return grouped
1164
1164
1165 def _repo_size(self):
1165 def _repo_size(self):
1166 from rhodecode.lib import helpers as h
1166 from rhodecode.lib import helpers as h
1167 log.debug('calculating repository size...')
1167 log.debug('calculating repository size...')
1168 return h.format_byte_size(self.scm_instance.size)
1168 return h.format_byte_size(self.scm_instance.size)
1169
1169
1170 #==========================================================================
1170 #==========================================================================
1171 # SCM CACHE INSTANCE
1171 # SCM CACHE INSTANCE
1172 #==========================================================================
1172 #==========================================================================
1173
1173
1174 def set_invalidate(self):
1174 def set_invalidate(self):
1175 """
1175 """
1176 Mark caches of this repo as invalid.
1176 Mark caches of this repo as invalid.
1177 """
1177 """
1178 CacheInvalidation.set_invalidate(self.repo_name)
1178 CacheInvalidation.set_invalidate(self.repo_name)
1179
1179
1180 def scm_instance_no_cache(self):
1180 def scm_instance_no_cache(self):
1181 return self.__get_instance()
1181 return self.__get_instance()
1182
1182
1183 @property
1183 @property
1184 def scm_instance(self):
1184 def scm_instance(self):
1185 import rhodecode
1185 import rhodecode
1186 full_cache = str2bool(rhodecode.CONFIG.get('vcs_full_cache'))
1186 full_cache = str2bool(rhodecode.CONFIG.get('vcs_full_cache'))
1187 if full_cache:
1187 if full_cache:
1188 return self.scm_instance_cached()
1188 return self.scm_instance_cached()
1189 return self.__get_instance()
1189 return self.__get_instance()
1190
1190
1191 def scm_instance_cached(self, valid_cache_keys=None):
1191 def scm_instance_cached(self, valid_cache_keys=None):
1192 @cache_region('long_term')
1192 @cache_region('long_term')
1193 def _c(repo_name):
1193 def _c(repo_name):
1194 return self.__get_instance()
1194 return self.__get_instance()
1195 rn = self.repo_name
1195 rn = self.repo_name
1196
1196
1197 valid = CacheInvalidation.test_and_set_valid(rn, None, valid_cache_keys=valid_cache_keys)
1197 valid = CacheInvalidation.test_and_set_valid(rn, None, valid_cache_keys=valid_cache_keys)
1198 if not valid:
1198 if not valid:
1199 log.debug('Cache for %s invalidated, getting new object' % (rn))
1199 log.debug('Cache for %s invalidated, getting new object' % (rn))
1200 region_invalidate(_c, None, rn)
1200 region_invalidate(_c, None, rn)
1201 else:
1201 else:
1202 log.debug('Getting obj for %s from cache' % (rn))
1202 log.debug('Getting obj for %s from cache' % (rn))
1203 return _c(rn)
1203 return _c(rn)
1204
1204
1205 def __get_instance(self):
1205 def __get_instance(self):
1206 repo_full_path = self.repo_full_path
1206 repo_full_path = self.repo_full_path
1207 try:
1207 try:
1208 alias = get_scm(repo_full_path)[0]
1208 alias = get_scm(repo_full_path)[0]
1209 log.debug('Creating instance of %s repository from %s'
1209 log.debug('Creating instance of %s repository from %s'
1210 % (alias, repo_full_path))
1210 % (alias, repo_full_path))
1211 backend = get_backend(alias)
1211 backend = get_backend(alias)
1212 except VCSError:
1212 except VCSError:
1213 log.error(traceback.format_exc())
1213 log.error(traceback.format_exc())
1214 log.error('Perhaps this repository is in db and not in '
1214 log.error('Perhaps this repository is in db and not in '
1215 'filesystem run rescan repositories with '
1215 'filesystem run rescan repositories with '
1216 '"destroy old data " option from admin panel')
1216 '"destroy old data " option from admin panel')
1217 return
1217 return
1218
1218
1219 if alias == 'hg':
1219 if alias == 'hg':
1220
1220
1221 repo = backend(safe_str(repo_full_path), create=False,
1221 repo = backend(safe_str(repo_full_path), create=False,
1222 baseui=self._ui)
1222 baseui=self._ui)
1223 # skip hidden web repository
1223 # skip hidden web repository
1224 if repo._get_hidden():
1224 if repo._get_hidden():
1225 return
1225 return
1226 else:
1226 else:
1227 repo = backend(repo_full_path, create=False)
1227 repo = backend(repo_full_path, create=False)
1228
1228
1229 return repo
1229 return repo
1230
1230
1231
1231
1232 class RepoGroup(Base, BaseModel):
1232 class RepoGroup(Base, BaseModel):
1233 __tablename__ = 'groups'
1233 __tablename__ = 'groups'
1234 __table_args__ = (
1234 __table_args__ = (
1235 UniqueConstraint('group_name', 'group_parent_id'),
1235 UniqueConstraint('group_name', 'group_parent_id'),
1236 CheckConstraint('group_id != group_parent_id'),
1236 CheckConstraint('group_id != group_parent_id'),
1237 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1237 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1238 'mysql_charset': 'utf8'},
1238 'mysql_charset': 'utf8'},
1239 )
1239 )
1240 __mapper_args__ = {'order_by': 'group_name'}
1240 __mapper_args__ = {'order_by': 'group_name'}
1241
1241
1242 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1242 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1243 group_name = Column("group_name", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
1243 group_name = Column("group_name", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
1244 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
1244 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
1245 group_description = Column("group_description", String(10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1245 group_description = Column("group_description", String(10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1246 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
1246 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
1247 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
1247 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
1248
1248
1249 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
1249 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
1250 users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
1250 users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
1251 parent_group = relationship('RepoGroup', remote_side=group_id)
1251 parent_group = relationship('RepoGroup', remote_side=group_id)
1252 user = relationship('User')
1252 user = relationship('User')
1253
1253
1254 def __init__(self, group_name='', parent_group=None):
1254 def __init__(self, group_name='', parent_group=None):
1255 self.group_name = group_name
1255 self.group_name = group_name
1256 self.parent_group = parent_group
1256 self.parent_group = parent_group
1257
1257
1258 def __unicode__(self):
1258 def __unicode__(self):
1259 return u"<%s('id:%s:%s')>" % (self.__class__.__name__, self.group_id,
1259 return u"<%s('id:%s:%s')>" % (self.__class__.__name__, self.group_id,
1260 self.group_name)
1260 self.group_name)
1261
1261
1262 @classmethod
1262 @classmethod
1263 def groups_choices(cls, groups=None, show_empty_group=True):
1263 def groups_choices(cls, groups=None, show_empty_group=True):
1264 from webhelpers.html import literal as _literal
1264 from webhelpers.html import literal as _literal
1265 if not groups:
1265 if not groups:
1266 groups = cls.query().all()
1266 groups = cls.query().all()
1267
1267
1268 repo_groups = []
1268 repo_groups = []
1269 if show_empty_group:
1269 if show_empty_group:
1270 repo_groups = [('-1', '-- %s --' % _('top level'))]
1270 repo_groups = [('-1', '-- %s --' % _('top level'))]
1271 sep = ' &raquo; '
1271 sep = ' &raquo; '
1272 _name = lambda k: _literal(sep.join(k))
1272 _name = lambda k: _literal(sep.join(k))
1273
1273
1274 repo_groups.extend([(x.group_id, _name(x.full_path_splitted))
1274 repo_groups.extend([(x.group_id, _name(x.full_path_splitted))
1275 for x in groups])
1275 for x in groups])
1276
1276
1277 repo_groups = sorted(repo_groups, key=lambda t: t[1].split(sep)[0])
1277 repo_groups = sorted(repo_groups, key=lambda t: t[1].split(sep)[0])
1278 return repo_groups
1278 return repo_groups
1279
1279
1280 @classmethod
1280 @classmethod
1281 def url_sep(cls):
1281 def url_sep(cls):
1282 return URL_SEP
1282 return URL_SEP
1283
1283
1284 @classmethod
1284 @classmethod
1285 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
1285 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
1286 if case_insensitive:
1286 if case_insensitive:
1287 gr = cls.query()\
1287 gr = cls.query()\
1288 .filter(cls.group_name.ilike(group_name))
1288 .filter(cls.group_name.ilike(group_name))
1289 else:
1289 else:
1290 gr = cls.query()\
1290 gr = cls.query()\
1291 .filter(cls.group_name == group_name)
1291 .filter(cls.group_name == group_name)
1292 if cache:
1292 if cache:
1293 gr = gr.options(FromCache(
1293 gr = gr.options(FromCache(
1294 "sql_cache_short",
1294 "sql_cache_short",
1295 "get_group_%s" % _hash_key(group_name)
1295 "get_group_%s" % _hash_key(group_name)
1296 )
1296 )
1297 )
1297 )
1298 return gr.scalar()
1298 return gr.scalar()
1299
1299
1300 @property
1300 @property
1301 def parents(self):
1301 def parents(self):
1302 parents_recursion_limit = 5
1302 parents_recursion_limit = 5
1303 groups = []
1303 groups = []
1304 if self.parent_group is None:
1304 if self.parent_group is None:
1305 return groups
1305 return groups
1306 cur_gr = self.parent_group
1306 cur_gr = self.parent_group
1307 groups.insert(0, cur_gr)
1307 groups.insert(0, cur_gr)
1308 cnt = 0
1308 cnt = 0
1309 while 1:
1309 while 1:
1310 cnt += 1
1310 cnt += 1
1311 gr = getattr(cur_gr, 'parent_group', None)
1311 gr = getattr(cur_gr, 'parent_group', None)
1312 cur_gr = cur_gr.parent_group
1312 cur_gr = cur_gr.parent_group
1313 if gr is None:
1313 if gr is None:
1314 break
1314 break
1315 if cnt == parents_recursion_limit:
1315 if cnt == parents_recursion_limit:
1316 # this will prevent accidental infinit loops
1316 # this will prevent accidental infinit loops
1317 log.error('group nested more than %s' %
1317 log.error('group nested more than %s' %
1318 parents_recursion_limit)
1318 parents_recursion_limit)
1319 break
1319 break
1320
1320
1321 groups.insert(0, gr)
1321 groups.insert(0, gr)
1322 return groups
1322 return groups
1323
1323
1324 @property
1324 @property
1325 def children(self):
1325 def children(self):
1326 return RepoGroup.query().filter(RepoGroup.parent_group == self)
1326 return RepoGroup.query().filter(RepoGroup.parent_group == self)
1327
1327
1328 @property
1328 @property
1329 def name(self):
1329 def name(self):
1330 return self.group_name.split(RepoGroup.url_sep())[-1]
1330 return self.group_name.split(RepoGroup.url_sep())[-1]
1331
1331
1332 @property
1332 @property
1333 def full_path(self):
1333 def full_path(self):
1334 return self.group_name
1334 return self.group_name
1335
1335
1336 @property
1336 @property
1337 def full_path_splitted(self):
1337 def full_path_splitted(self):
1338 return self.group_name.split(RepoGroup.url_sep())
1338 return self.group_name.split(RepoGroup.url_sep())
1339
1339
1340 @property
1340 @property
1341 def repositories(self):
1341 def repositories(self):
1342 return Repository.query()\
1342 return Repository.query()\
1343 .filter(Repository.group == self)\
1343 .filter(Repository.group == self)\
1344 .order_by(Repository.repo_name)
1344 .order_by(Repository.repo_name)
1345
1345
1346 @property
1346 @property
1347 def repositories_recursive_count(self):
1347 def repositories_recursive_count(self):
1348 cnt = self.repositories.count()
1348 cnt = self.repositories.count()
1349
1349
1350 def children_count(group):
1350 def children_count(group):
1351 cnt = 0
1351 cnt = 0
1352 for child in group.children:
1352 for child in group.children:
1353 cnt += child.repositories.count()
1353 cnt += child.repositories.count()
1354 cnt += children_count(child)
1354 cnt += children_count(child)
1355 return cnt
1355 return cnt
1356
1356
1357 return cnt + children_count(self)
1357 return cnt + children_count(self)
1358
1358
1359 def _recursive_objects(self, include_repos=True):
1359 def _recursive_objects(self, include_repos=True):
1360 all_ = []
1360 all_ = []
1361
1361
1362 def _get_members(root_gr):
1362 def _get_members(root_gr):
1363 if include_repos:
1363 if include_repos:
1364 for r in root_gr.repositories:
1364 for r in root_gr.repositories:
1365 all_.append(r)
1365 all_.append(r)
1366 childs = root_gr.children.all()
1366 childs = root_gr.children.all()
1367 if childs:
1367 if childs:
1368 for gr in childs:
1368 for gr in childs:
1369 all_.append(gr)
1369 all_.append(gr)
1370 _get_members(gr)
1370 _get_members(gr)
1371
1371
1372 _get_members(self)
1372 _get_members(self)
1373 return [self] + all_
1373 return [self] + all_
1374
1374
1375 def recursive_groups_and_repos(self):
1375 def recursive_groups_and_repos(self):
1376 """
1376 """
1377 Recursive return all groups, with repositories in those groups
1377 Recursive return all groups, with repositories in those groups
1378 """
1378 """
1379 return self._recursive_objects()
1379 return self._recursive_objects()
1380
1380
1381 def recursive_groups(self):
1381 def recursive_groups(self):
1382 """
1382 """
1383 Returns all children groups for this group including children of children
1383 Returns all children groups for this group including children of children
1384 """
1384 """
1385 return self._recursive_objects(include_repos=False)
1385 return self._recursive_objects(include_repos=False)
1386
1386
1387 def get_new_name(self, group_name):
1387 def get_new_name(self, group_name):
1388 """
1388 """
1389 returns new full group name based on parent and new name
1389 returns new full group name based on parent and new name
1390
1390
1391 :param group_name:
1391 :param group_name:
1392 """
1392 """
1393 path_prefix = (self.parent_group.full_path_splitted if
1393 path_prefix = (self.parent_group.full_path_splitted if
1394 self.parent_group else [])
1394 self.parent_group else [])
1395 return RepoGroup.url_sep().join(path_prefix + [group_name])
1395 return RepoGroup.url_sep().join(path_prefix + [group_name])
1396
1396
1397
1397
1398 class Permission(Base, BaseModel):
1398 class Permission(Base, BaseModel):
1399 __tablename__ = 'permissions'
1399 __tablename__ = 'permissions'
1400 __table_args__ = (
1400 __table_args__ = (
1401 Index('p_perm_name_idx', 'permission_name'),
1401 Index('p_perm_name_idx', 'permission_name'),
1402 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1402 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1403 'mysql_charset': 'utf8'},
1403 'mysql_charset': 'utf8'},
1404 )
1404 )
1405 PERMS = [
1405 PERMS = [
1406 ('hg.admin', _('RhodeCode Administrator')),
1406 ('hg.admin', _('RhodeCode Administrator')),
1407
1407
1408 ('repository.none', _('Repository no access')),
1408 ('repository.none', _('Repository no access')),
1409 ('repository.read', _('Repository read access')),
1409 ('repository.read', _('Repository read access')),
1410 ('repository.write', _('Repository write access')),
1410 ('repository.write', _('Repository write access')),
1411 ('repository.admin', _('Repository admin access')),
1411 ('repository.admin', _('Repository admin access')),
1412
1412
1413 ('group.none', _('Repository group no access')),
1413 ('group.none', _('Repository group no access')),
1414 ('group.read', _('Repository group read access')),
1414 ('group.read', _('Repository group read access')),
1415 ('group.write', _('Repository group write access')),
1415 ('group.write', _('Repository group write access')),
1416 ('group.admin', _('Repository group admin access')),
1416 ('group.admin', _('Repository group admin access')),
1417
1417
1418 ('usergroup.none', _('User group no access')),
1418 ('usergroup.none', _('User group no access')),
1419 ('usergroup.read', _('User group read access')),
1419 ('usergroup.read', _('User group read access')),
1420 ('usergroup.write', _('User group write access')),
1420 ('usergroup.write', _('User group write access')),
1421 ('usergroup.admin', _('User group admin access')),
1421 ('usergroup.admin', _('User group admin access')),
1422
1422
1423 ('hg.repogroup.create.false', _('Repository Group creation disabled')),
1423 ('hg.repogroup.create.false', _('Repository Group creation disabled')),
1424 ('hg.repogroup.create.true', _('Repository Group creation enabled')),
1424 ('hg.repogroup.create.true', _('Repository Group creation enabled')),
1425
1425
1426 ('hg.usergroup.create.false', _('User Group creation disabled')),
1426 ('hg.usergroup.create.false', _('User Group creation disabled')),
1427 ('hg.usergroup.create.true', _('User Group creation enabled')),
1427 ('hg.usergroup.create.true', _('User Group creation enabled')),
1428
1428
1429 ('hg.create.none', _('Repository creation disabled')),
1429 ('hg.create.none', _('Repository creation disabled')),
1430 ('hg.create.repository', _('Repository creation enabled')),
1430 ('hg.create.repository', _('Repository creation enabled')),
1431
1431
1432 ('hg.fork.none', _('Repository forking disabled')),
1432 ('hg.fork.none', _('Repository forking disabled')),
1433 ('hg.fork.repository', _('Repository forking enabled')),
1433 ('hg.fork.repository', _('Repository forking enabled')),
1434
1434
1435 ('hg.register.none', _('Registration disabled')),
1435 ('hg.register.none', _('Registration disabled')),
1436 ('hg.register.manual_activate', _('User Registration with manual account activation')),
1436 ('hg.register.manual_activate', _('User Registration with manual account activation')),
1437 ('hg.register.auto_activate', _('User Registration with automatic account activation')),
1437 ('hg.register.auto_activate', _('User Registration with automatic account activation')),
1438
1438
1439 ('hg.extern_activate.manual', _('Manual activation of external account')),
1439 ('hg.extern_activate.manual', _('Manual activation of external account')),
1440 ('hg.extern_activate.auto', _('Automatic activation of external account')),
1440 ('hg.extern_activate.auto', _('Automatic activation of external account')),
1441
1441
1442 ]
1442 ]
1443
1443
1444 #definition of system default permissions for DEFAULT user
1444 #definition of system default permissions for DEFAULT user
1445 DEFAULT_USER_PERMISSIONS = [
1445 DEFAULT_USER_PERMISSIONS = [
1446 'repository.read',
1446 'repository.read',
1447 'group.read',
1447 'group.read',
1448 'usergroup.read',
1448 'usergroup.read',
1449 'hg.create.repository',
1449 'hg.create.repository',
1450 'hg.fork.repository',
1450 'hg.fork.repository',
1451 'hg.register.manual_activate',
1451 'hg.register.manual_activate',
1452 'hg.extern_activate.auto',
1452 'hg.extern_activate.auto',
1453 ]
1453 ]
1454
1454
1455 # defines which permissions are more important higher the more important
1455 # defines which permissions are more important higher the more important
1456 # Weight defines which permissions are more important.
1456 # Weight defines which permissions are more important.
1457 # The higher number the more important.
1457 # The higher number the more important.
1458 PERM_WEIGHTS = {
1458 PERM_WEIGHTS = {
1459 'repository.none': 0,
1459 'repository.none': 0,
1460 'repository.read': 1,
1460 'repository.read': 1,
1461 'repository.write': 3,
1461 'repository.write': 3,
1462 'repository.admin': 4,
1462 'repository.admin': 4,
1463
1463
1464 'group.none': 0,
1464 'group.none': 0,
1465 'group.read': 1,
1465 'group.read': 1,
1466 'group.write': 3,
1466 'group.write': 3,
1467 'group.admin': 4,
1467 'group.admin': 4,
1468
1468
1469 'usergroup.none': 0,
1469 'usergroup.none': 0,
1470 'usergroup.read': 1,
1470 'usergroup.read': 1,
1471 'usergroup.write': 3,
1471 'usergroup.write': 3,
1472 'usergroup.admin': 4,
1472 'usergroup.admin': 4,
1473 'hg.repogroup.create.false': 0,
1473 'hg.repogroup.create.false': 0,
1474 'hg.repogroup.create.true': 1,
1474 'hg.repogroup.create.true': 1,
1475
1475
1476 'hg.usergroup.create.false': 0,
1476 'hg.usergroup.create.false': 0,
1477 'hg.usergroup.create.true': 1,
1477 'hg.usergroup.create.true': 1,
1478
1478
1479 'hg.fork.none': 0,
1479 'hg.fork.none': 0,
1480 'hg.fork.repository': 1,
1480 'hg.fork.repository': 1,
1481 'hg.create.none': 0,
1481 'hg.create.none': 0,
1482 'hg.create.repository': 1
1482 'hg.create.repository': 1
1483 }
1483 }
1484
1484
1485 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1485 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1486 permission_name = Column("permission_name", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1486 permission_name = Column("permission_name", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1487 permission_longname = Column("permission_longname", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1487 permission_longname = Column("permission_longname", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1488
1488
1489 def __unicode__(self):
1489 def __unicode__(self):
1490 return u"<%s('%s:%s')>" % (
1490 return u"<%s('%s:%s')>" % (
1491 self.__class__.__name__, self.permission_id, self.permission_name
1491 self.__class__.__name__, self.permission_id, self.permission_name
1492 )
1492 )
1493
1493
1494 @classmethod
1494 @classmethod
1495 def get_by_key(cls, key):
1495 def get_by_key(cls, key):
1496 return cls.query().filter(cls.permission_name == key).scalar()
1496 return cls.query().filter(cls.permission_name == key).scalar()
1497
1497
1498 @classmethod
1498 @classmethod
1499 def get_default_perms(cls, default_user_id):
1499 def get_default_perms(cls, default_user_id):
1500 q = Session().query(UserRepoToPerm, Repository, cls)\
1500 q = Session().query(UserRepoToPerm, Repository, cls)\
1501 .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
1501 .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
1502 .join((cls, UserRepoToPerm.permission_id == cls.permission_id))\
1502 .join((cls, UserRepoToPerm.permission_id == cls.permission_id))\
1503 .filter(UserRepoToPerm.user_id == default_user_id)
1503 .filter(UserRepoToPerm.user_id == default_user_id)
1504
1504
1505 return q.all()
1505 return q.all()
1506
1506
1507 @classmethod
1507 @classmethod
1508 def get_default_group_perms(cls, default_user_id):
1508 def get_default_group_perms(cls, default_user_id):
1509 q = Session().query(UserRepoGroupToPerm, RepoGroup, cls)\
1509 q = Session().query(UserRepoGroupToPerm, RepoGroup, cls)\
1510 .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
1510 .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
1511 .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id))\
1511 .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id))\
1512 .filter(UserRepoGroupToPerm.user_id == default_user_id)
1512 .filter(UserRepoGroupToPerm.user_id == default_user_id)
1513
1513
1514 return q.all()
1514 return q.all()
1515
1515
1516 @classmethod
1516 @classmethod
1517 def get_default_user_group_perms(cls, default_user_id):
1517 def get_default_user_group_perms(cls, default_user_id):
1518 q = Session().query(UserUserGroupToPerm, UserGroup, cls)\
1518 q = Session().query(UserUserGroupToPerm, UserGroup, cls)\
1519 .join((UserGroup, UserUserGroupToPerm.user_group_id == UserGroup.users_group_id))\
1519 .join((UserGroup, UserUserGroupToPerm.user_group_id == UserGroup.users_group_id))\
1520 .join((cls, UserUserGroupToPerm.permission_id == cls.permission_id))\
1520 .join((cls, UserUserGroupToPerm.permission_id == cls.permission_id))\
1521 .filter(UserUserGroupToPerm.user_id == default_user_id)
1521 .filter(UserUserGroupToPerm.user_id == default_user_id)
1522
1522
1523 return q.all()
1523 return q.all()
1524
1524
1525
1525
1526 class UserRepoToPerm(Base, BaseModel):
1526 class UserRepoToPerm(Base, BaseModel):
1527 __tablename__ = 'repo_to_perm'
1527 __tablename__ = 'repo_to_perm'
1528 __table_args__ = (
1528 __table_args__ = (
1529 UniqueConstraint('user_id', 'repository_id', 'permission_id'),
1529 UniqueConstraint('user_id', 'repository_id', 'permission_id'),
1530 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1530 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1531 'mysql_charset': 'utf8'}
1531 'mysql_charset': 'utf8'}
1532 )
1532 )
1533 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1533 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1534 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1534 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1535 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1535 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1536 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
1536 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
1537
1537
1538 user = relationship('User')
1538 user = relationship('User')
1539 repository = relationship('Repository')
1539 repository = relationship('Repository')
1540 permission = relationship('Permission')
1540 permission = relationship('Permission')
1541
1541
1542 @classmethod
1542 @classmethod
1543 def create(cls, user, repository, permission):
1543 def create(cls, user, repository, permission):
1544 n = cls()
1544 n = cls()
1545 n.user = user
1545 n.user = user
1546 n.repository = repository
1546 n.repository = repository
1547 n.permission = permission
1547 n.permission = permission
1548 Session().add(n)
1548 Session().add(n)
1549 return n
1549 return n
1550
1550
1551 def __unicode__(self):
1551 def __unicode__(self):
1552 return u'<%s => %s >' % (self.user, self.repository)
1552 return u'<%s => %s >' % (self.user, self.repository)
1553
1553
1554
1554
1555 class UserUserGroupToPerm(Base, BaseModel):
1555 class UserUserGroupToPerm(Base, BaseModel):
1556 __tablename__ = 'user_user_group_to_perm'
1556 __tablename__ = 'user_user_group_to_perm'
1557 __table_args__ = (
1557 __table_args__ = (
1558 UniqueConstraint('user_id', 'user_group_id', 'permission_id'),
1558 UniqueConstraint('user_id', 'user_group_id', 'permission_id'),
1559 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1559 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1560 'mysql_charset': 'utf8'}
1560 'mysql_charset': 'utf8'}
1561 )
1561 )
1562 user_user_group_to_perm_id = Column("user_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1562 user_user_group_to_perm_id = Column("user_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1563 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1563 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1564 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1564 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1565 user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1565 user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1566
1566
1567 user = relationship('User')
1567 user = relationship('User')
1568 user_group = relationship('UserGroup')
1568 user_group = relationship('UserGroup')
1569 permission = relationship('Permission')
1569 permission = relationship('Permission')
1570
1570
1571 @classmethod
1571 @classmethod
1572 def create(cls, user, user_group, permission):
1572 def create(cls, user, user_group, permission):
1573 n = cls()
1573 n = cls()
1574 n.user = user
1574 n.user = user
1575 n.user_group = user_group
1575 n.user_group = user_group
1576 n.permission = permission
1576 n.permission = permission
1577 Session().add(n)
1577 Session().add(n)
1578 return n
1578 return n
1579
1579
1580 def __unicode__(self):
1580 def __unicode__(self):
1581 return u'<%s => %s >' % (self.user, self.user_group)
1581 return u'<%s => %s >' % (self.user, self.user_group)
1582
1582
1583
1583
1584 class UserToPerm(Base, BaseModel):
1584 class UserToPerm(Base, BaseModel):
1585 __tablename__ = 'user_to_perm'
1585 __tablename__ = 'user_to_perm'
1586 __table_args__ = (
1586 __table_args__ = (
1587 UniqueConstraint('user_id', 'permission_id'),
1587 UniqueConstraint('user_id', 'permission_id'),
1588 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1588 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1589 'mysql_charset': 'utf8'}
1589 'mysql_charset': 'utf8'}
1590 )
1590 )
1591 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1591 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1592 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1592 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1593 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1593 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1594
1594
1595 user = relationship('User')
1595 user = relationship('User')
1596 permission = relationship('Permission', lazy='joined')
1596 permission = relationship('Permission', lazy='joined')
1597
1597
1598 def __unicode__(self):
1598 def __unicode__(self):
1599 return u'<%s => %s >' % (self.user, self.permission)
1599 return u'<%s => %s >' % (self.user, self.permission)
1600
1600
1601
1601
1602 class UserGroupRepoToPerm(Base, BaseModel):
1602 class UserGroupRepoToPerm(Base, BaseModel):
1603 __tablename__ = 'users_group_repo_to_perm'
1603 __tablename__ = 'users_group_repo_to_perm'
1604 __table_args__ = (
1604 __table_args__ = (
1605 UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
1605 UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
1606 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1606 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1607 'mysql_charset': 'utf8'}
1607 'mysql_charset': 'utf8'}
1608 )
1608 )
1609 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1609 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1610 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1610 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1611 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1611 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1612 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
1612 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
1613
1613
1614 users_group = relationship('UserGroup')
1614 users_group = relationship('UserGroup')
1615 permission = relationship('Permission')
1615 permission = relationship('Permission')
1616 repository = relationship('Repository')
1616 repository = relationship('Repository')
1617
1617
1618 @classmethod
1618 @classmethod
1619 def create(cls, users_group, repository, permission):
1619 def create(cls, users_group, repository, permission):
1620 n = cls()
1620 n = cls()
1621 n.users_group = users_group
1621 n.users_group = users_group
1622 n.repository = repository
1622 n.repository = repository
1623 n.permission = permission
1623 n.permission = permission
1624 Session().add(n)
1624 Session().add(n)
1625 return n
1625 return n
1626
1626
1627 def __unicode__(self):
1627 def __unicode__(self):
1628 return u'<UserGroupRepoToPerm:%s => %s >' % (self.users_group, self.repository)
1628 return u'<UserGroupRepoToPerm:%s => %s >' % (self.users_group, self.repository)
1629
1629
1630
1630
1631 class UserGroupUserGroupToPerm(Base, BaseModel):
1631 class UserGroupUserGroupToPerm(Base, BaseModel):
1632 __tablename__ = 'user_group_user_group_to_perm'
1632 __tablename__ = 'user_group_user_group_to_perm'
1633 __table_args__ = (
1633 __table_args__ = (
1634 UniqueConstraint('target_user_group_id', 'user_group_id', 'permission_id'),
1634 UniqueConstraint('target_user_group_id', 'user_group_id', 'permission_id'),
1635 CheckConstraint('target_user_group_id != user_group_id'),
1635 CheckConstraint('target_user_group_id != user_group_id'),
1636 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1636 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1637 'mysql_charset': 'utf8'}
1637 'mysql_charset': 'utf8'}
1638 )
1638 )
1639 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)
1639 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)
1640 target_user_group_id = Column("target_user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1640 target_user_group_id = Column("target_user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1641 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1641 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1642 user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1642 user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1643
1643
1644 target_user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id')
1644 target_user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id')
1645 user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.user_group_id==UserGroup.users_group_id')
1645 user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.user_group_id==UserGroup.users_group_id')
1646 permission = relationship('Permission')
1646 permission = relationship('Permission')
1647
1647
1648 @classmethod
1648 @classmethod
1649 def create(cls, target_user_group, user_group, permission):
1649 def create(cls, target_user_group, user_group, permission):
1650 n = cls()
1650 n = cls()
1651 n.target_user_group = target_user_group
1651 n.target_user_group = target_user_group
1652 n.user_group = user_group
1652 n.user_group = user_group
1653 n.permission = permission
1653 n.permission = permission
1654 Session().add(n)
1654 Session().add(n)
1655 return n
1655 return n
1656
1656
1657 def __unicode__(self):
1657 def __unicode__(self):
1658 return u'<UserGroupUserGroup:%s => %s >' % (self.target_user_group, self.user_group)
1658 return u'<UserGroupUserGroup:%s => %s >' % (self.target_user_group, self.user_group)
1659
1659
1660
1660
1661 class UserGroupToPerm(Base, BaseModel):
1661 class UserGroupToPerm(Base, BaseModel):
1662 __tablename__ = 'users_group_to_perm'
1662 __tablename__ = 'users_group_to_perm'
1663 __table_args__ = (
1663 __table_args__ = (
1664 UniqueConstraint('users_group_id', 'permission_id',),
1664 UniqueConstraint('users_group_id', 'permission_id',),
1665 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1665 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1666 'mysql_charset': 'utf8'}
1666 'mysql_charset': 'utf8'}
1667 )
1667 )
1668 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1668 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1669 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1669 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1670 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1670 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1671
1671
1672 users_group = relationship('UserGroup')
1672 users_group = relationship('UserGroup')
1673 permission = relationship('Permission')
1673 permission = relationship('Permission')
1674
1674
1675
1675
1676 class UserRepoGroupToPerm(Base, BaseModel):
1676 class UserRepoGroupToPerm(Base, BaseModel):
1677 __tablename__ = 'user_repo_group_to_perm'
1677 __tablename__ = 'user_repo_group_to_perm'
1678 __table_args__ = (
1678 __table_args__ = (
1679 UniqueConstraint('user_id', 'group_id', 'permission_id'),
1679 UniqueConstraint('user_id', 'group_id', 'permission_id'),
1680 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1680 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1681 'mysql_charset': 'utf8'}
1681 'mysql_charset': 'utf8'}
1682 )
1682 )
1683
1683
1684 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1684 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1685 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1685 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1686 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
1686 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
1687 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1687 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1688
1688
1689 user = relationship('User')
1689 user = relationship('User')
1690 group = relationship('RepoGroup')
1690 group = relationship('RepoGroup')
1691 permission = relationship('Permission')
1691 permission = relationship('Permission')
1692
1692
1693
1693
1694 class UserGroupRepoGroupToPerm(Base, BaseModel):
1694 class UserGroupRepoGroupToPerm(Base, BaseModel):
1695 __tablename__ = 'users_group_repo_group_to_perm'
1695 __tablename__ = 'users_group_repo_group_to_perm'
1696 __table_args__ = (
1696 __table_args__ = (
1697 UniqueConstraint('users_group_id', 'group_id'),
1697 UniqueConstraint('users_group_id', 'group_id'),
1698 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1698 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1699 'mysql_charset': 'utf8'}
1699 'mysql_charset': 'utf8'}
1700 )
1700 )
1701
1701
1702 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)
1702 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)
1703 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1703 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1704 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
1704 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
1705 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1705 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1706
1706
1707 users_group = relationship('UserGroup')
1707 users_group = relationship('UserGroup')
1708 permission = relationship('Permission')
1708 permission = relationship('Permission')
1709 group = relationship('RepoGroup')
1709 group = relationship('RepoGroup')
1710
1710
1711
1711
1712 class Statistics(Base, BaseModel):
1712 class Statistics(Base, BaseModel):
1713 __tablename__ = 'statistics'
1713 __tablename__ = 'statistics'
1714 __table_args__ = (
1714 __table_args__ = (
1715 UniqueConstraint('repository_id'),
1715 UniqueConstraint('repository_id'),
1716 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1716 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1717 'mysql_charset': 'utf8'}
1717 'mysql_charset': 'utf8'}
1718 )
1718 )
1719 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1719 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1720 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
1720 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
1721 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
1721 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
1722 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
1722 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
1723 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
1723 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
1724 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
1724 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
1725
1725
1726 repository = relationship('Repository', single_parent=True)
1726 repository = relationship('Repository', single_parent=True)
1727
1727
1728
1728
1729 class UserFollowing(Base, BaseModel):
1729 class UserFollowing(Base, BaseModel):
1730 __tablename__ = 'user_followings'
1730 __tablename__ = 'user_followings'
1731 __table_args__ = (
1731 __table_args__ = (
1732 UniqueConstraint('user_id', 'follows_repository_id'),
1732 UniqueConstraint('user_id', 'follows_repository_id'),
1733 UniqueConstraint('user_id', 'follows_user_id'),
1733 UniqueConstraint('user_id', 'follows_user_id'),
1734 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1734 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1735 'mysql_charset': 'utf8'}
1735 'mysql_charset': 'utf8'}
1736 )
1736 )
1737
1737
1738 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1738 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1739 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1739 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1740 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
1740 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
1741 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
1741 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
1742 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
1742 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
1743
1743
1744 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
1744 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
1745
1745
1746 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
1746 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
1747 follows_repository = relationship('Repository', order_by='Repository.repo_name')
1747 follows_repository = relationship('Repository', order_by='Repository.repo_name')
1748
1748
1749 @classmethod
1749 @classmethod
1750 def get_repo_followers(cls, repo_id):
1750 def get_repo_followers(cls, repo_id):
1751 return cls.query().filter(cls.follows_repo_id == repo_id)
1751 return cls.query().filter(cls.follows_repo_id == repo_id)
1752
1752
1753
1753
1754 class CacheInvalidation(Base, BaseModel):
1754 class CacheInvalidation(Base, BaseModel):
1755 __tablename__ = 'cache_invalidation'
1755 __tablename__ = 'cache_invalidation'
1756 __table_args__ = (
1756 __table_args__ = (
1757 UniqueConstraint('cache_key'),
1757 UniqueConstraint('cache_key'),
1758 Index('key_idx', 'cache_key'),
1758 Index('key_idx', 'cache_key'),
1759 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1759 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1760 'mysql_charset': 'utf8'},
1760 'mysql_charset': 'utf8'},
1761 )
1761 )
1762 # cache_id, not used
1762 # cache_id, not used
1763 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1763 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1764 # cache_key as created by _get_cache_key
1764 # cache_key as created by _get_cache_key
1765 cache_key = Column("cache_key", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1765 cache_key = Column("cache_key", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1766 # cache_args is a repo_name
1766 # cache_args is a repo_name
1767 cache_args = Column("cache_args", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1767 cache_args = Column("cache_args", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1768 # instance sets cache_active True when it is caching,
1768 # instance sets cache_active True when it is caching,
1769 # other instances set cache_active to False to indicate that this cache is invalid
1769 # other instances set cache_active to False to indicate that this cache is invalid
1770 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
1770 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
1771
1771
1772 def __init__(self, cache_key, repo_name=''):
1772 def __init__(self, cache_key, repo_name=''):
1773 self.cache_key = cache_key
1773 self.cache_key = cache_key
1774 self.cache_args = repo_name
1774 self.cache_args = repo_name
1775 self.cache_active = False
1775 self.cache_active = False
1776
1776
1777 def __unicode__(self):
1777 def __unicode__(self):
1778 return u"<%s('%s:%s[%s]')>" % (self.__class__.__name__,
1778 return u"<%s('%s:%s[%s]')>" % (self.__class__.__name__,
1779 self.cache_id, self.cache_key, self.cache_active)
1779 self.cache_id, self.cache_key, self.cache_active)
1780
1780
1781 def _cache_key_partition(self):
1781 def _cache_key_partition(self):
1782 prefix, repo_name, suffix = self.cache_key.partition(self.cache_args)
1782 prefix, repo_name, suffix = self.cache_key.partition(self.cache_args)
1783 return prefix, repo_name, suffix
1783 return prefix, repo_name, suffix
1784
1784
1785 def get_prefix(self):
1785 def get_prefix(self):
1786 """
1786 """
1787 get prefix that might have been used in _get_cache_key to
1787 get prefix that might have been used in _get_cache_key to
1788 generate self.cache_key. Only used for informational purposes
1788 generate self.cache_key. Only used for informational purposes
1789 in repo_edit.html.
1789 in repo_edit.html.
1790 """
1790 """
1791 # prefix, repo_name, suffix
1791 # prefix, repo_name, suffix
1792 return self._cache_key_partition()[0]
1792 return self._cache_key_partition()[0]
1793
1793
1794 def get_suffix(self):
1794 def get_suffix(self):
1795 """
1795 """
1796 get suffix that might have been used in _get_cache_key to
1796 get suffix that might have been used in _get_cache_key to
1797 generate self.cache_key. Only used for informational purposes
1797 generate self.cache_key. Only used for informational purposes
1798 in repo_edit.html.
1798 in repo_edit.html.
1799 """
1799 """
1800 # prefix, repo_name, suffix
1800 # prefix, repo_name, suffix
1801 return self._cache_key_partition()[2]
1801 return self._cache_key_partition()[2]
1802
1802
1803 @classmethod
1803 @classmethod
1804 def clear_cache(cls):
1804 def clear_cache(cls):
1805 """
1805 """
1806 Delete all cache keys from database.
1806 Delete all cache keys from database.
1807 Should only be run when all instances are down and all entries thus stale.
1807 Should only be run when all instances are down and all entries thus stale.
1808 """
1808 """
1809 cls.query().delete()
1809 cls.query().delete()
1810 Session().commit()
1810 Session().commit()
1811
1811
1812 @classmethod
1812 @classmethod
1813 def _get_cache_key(cls, key):
1813 def _get_cache_key(cls, key):
1814 """
1814 """
1815 Wrapper for generating a unique cache key for this instance and "key".
1815 Wrapper for generating a unique cache key for this instance and "key".
1816 key must / will start with a repo_name which will be stored in .cache_args .
1816 key must / will start with a repo_name which will be stored in .cache_args .
1817 """
1817 """
1818 import rhodecode
1818 import rhodecode
1819 prefix = rhodecode.CONFIG.get('instance_id', '')
1819 prefix = rhodecode.CONFIG.get('instance_id', '')
1820 return "%s%s" % (prefix, key)
1820 return "%s%s" % (prefix, key)
1821
1821
1822 @classmethod
1822 @classmethod
1823 def set_invalidate(cls, repo_name):
1823 def set_invalidate(cls, repo_name):
1824 """
1824 """
1825 Mark all caches of a repo as invalid in the database.
1825 Mark all caches of a repo as invalid in the database.
1826 """
1826 """
1827 inv_objs = Session().query(cls).filter(cls.cache_args == repo_name).all()
1827 inv_objs = Session().query(cls).filter(cls.cache_args == repo_name).all()
1828
1828
1829 try:
1829 try:
1830 for inv_obj in inv_objs:
1830 for inv_obj in inv_objs:
1831 log.debug('marking %s key for invalidation based on repo_name=%s'
1831 log.debug('marking %s key for invalidation based on repo_name=%s'
1832 % (inv_obj, safe_str(repo_name)))
1832 % (inv_obj, safe_str(repo_name)))
1833 inv_obj.cache_active = False
1833 inv_obj.cache_active = False
1834 Session().add(inv_obj)
1834 Session().add(inv_obj)
1835 Session().commit()
1835 Session().commit()
1836 except Exception:
1836 except Exception:
1837 log.error(traceback.format_exc())
1837 log.error(traceback.format_exc())
1838 Session().rollback()
1838 Session().rollback()
1839
1839
1840 @classmethod
1840 @classmethod
1841 def test_and_set_valid(cls, repo_name, kind, valid_cache_keys=None):
1841 def test_and_set_valid(cls, repo_name, kind, valid_cache_keys=None):
1842 """
1842 """
1843 Mark this cache key as active and currently cached.
1843 Mark this cache key as active and currently cached.
1844 Return True if the existing cache registration still was valid.
1844 Return True if the existing cache registration still was valid.
1845 Return False to indicate that it had been invalidated and caches should be refreshed.
1845 Return False to indicate that it had been invalidated and caches should be refreshed.
1846 """
1846 """
1847
1847
1848 key = (repo_name + '_' + kind) if kind else repo_name
1848 key = (repo_name + '_' + kind) if kind else repo_name
1849 cache_key = cls._get_cache_key(key)
1849 cache_key = cls._get_cache_key(key)
1850
1850
1851 if valid_cache_keys and cache_key in valid_cache_keys:
1851 if valid_cache_keys and cache_key in valid_cache_keys:
1852 return True
1852 return True
1853
1853
1854 try:
1854 try:
1855 inv_obj = cls.query().filter(cls.cache_key == cache_key).scalar()
1855 inv_obj = cls.query().filter(cls.cache_key == cache_key).scalar()
1856 if not inv_obj:
1856 if not inv_obj:
1857 inv_obj = CacheInvalidation(cache_key, repo_name)
1857 inv_obj = CacheInvalidation(cache_key, repo_name)
1858 was_valid = inv_obj.cache_active
1858 was_valid = inv_obj.cache_active
1859 inv_obj.cache_active = True
1859 inv_obj.cache_active = True
1860 Session().add(inv_obj)
1860 Session().add(inv_obj)
1861 Session().commit()
1861 Session().commit()
1862 return was_valid
1862 return was_valid
1863 except Exception:
1863 except Exception:
1864 log.error(traceback.format_exc())
1864 log.error(traceback.format_exc())
1865 Session().rollback()
1865 Session().rollback()
1866 return False
1866 return False
1867
1867
1868 @classmethod
1868 @classmethod
1869 def get_valid_cache_keys(cls):
1869 def get_valid_cache_keys(cls):
1870 """
1870 """
1871 Return opaque object with information of which caches still are valid
1871 Return opaque object with information of which caches still are valid
1872 and can be used without checking for invalidation.
1872 and can be used without checking for invalidation.
1873 """
1873 """
1874 return set(inv_obj.cache_key for inv_obj in cls.query().filter(cls.cache_active).all())
1874 return set(inv_obj.cache_key for inv_obj in cls.query().filter(cls.cache_active).all())
1875
1875
1876
1876
1877 class ChangesetComment(Base, BaseModel):
1877 class ChangesetComment(Base, BaseModel):
1878 __tablename__ = 'changeset_comments'
1878 __tablename__ = 'changeset_comments'
1879 __table_args__ = (
1879 __table_args__ = (
1880 Index('cc_revision_idx', 'revision'),
1880 Index('cc_revision_idx', 'revision'),
1881 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1881 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1882 'mysql_charset': 'utf8'},
1882 'mysql_charset': 'utf8'},
1883 )
1883 )
1884 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
1884 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
1885 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1885 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1886 revision = Column('revision', String(40), nullable=True)
1886 revision = Column('revision', String(40), nullable=True)
1887 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
1887 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
1888 line_no = Column('line_no', Unicode(10), nullable=True)
1888 line_no = Column('line_no', Unicode(10), nullable=True)
1889 hl_lines = Column('hl_lines', Unicode(512), nullable=True)
1889 hl_lines = Column('hl_lines', Unicode(512), nullable=True)
1890 f_path = Column('f_path', Unicode(1000), nullable=True)
1890 f_path = Column('f_path', Unicode(1000), nullable=True)
1891 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
1891 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
1892 text = Column('text', UnicodeText(25000), nullable=False)
1892 text = Column('text', UnicodeText(25000), nullable=False)
1893 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1893 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1894 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1894 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1895
1895
1896 author = relationship('User', lazy='joined')
1896 author = relationship('User', lazy='joined')
1897 repo = relationship('Repository')
1897 repo = relationship('Repository')
1898 status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan")
1898 status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan")
1899 pull_request = relationship('PullRequest', lazy='joined')
1899 pull_request = relationship('PullRequest', lazy='joined')
1900
1900
1901 @classmethod
1901 @classmethod
1902 def get_users(cls, revision=None, pull_request_id=None):
1902 def get_users(cls, revision=None, pull_request_id=None):
1903 """
1903 """
1904 Returns user associated with this ChangesetComment. ie those
1904 Returns user associated with this ChangesetComment. ie those
1905 who actually commented
1905 who actually commented
1906
1906
1907 :param cls:
1907 :param cls:
1908 :param revision:
1908 :param revision:
1909 """
1909 """
1910 q = Session().query(User)\
1910 q = Session().query(User)\
1911 .join(ChangesetComment.author)
1911 .join(ChangesetComment.author)
1912 if revision:
1912 if revision:
1913 q = q.filter(cls.revision == revision)
1913 q = q.filter(cls.revision == revision)
1914 elif pull_request_id:
1914 elif pull_request_id:
1915 q = q.filter(cls.pull_request_id == pull_request_id)
1915 q = q.filter(cls.pull_request_id == pull_request_id)
1916 return q.all()
1916 return q.all()
1917
1917
1918
1918
1919 class ChangesetStatus(Base, BaseModel):
1919 class ChangesetStatus(Base, BaseModel):
1920 __tablename__ = 'changeset_statuses'
1920 __tablename__ = 'changeset_statuses'
1921 __table_args__ = (
1921 __table_args__ = (
1922 Index('cs_revision_idx', 'revision'),
1922 Index('cs_revision_idx', 'revision'),
1923 Index('cs_version_idx', 'version'),
1923 Index('cs_version_idx', 'version'),
1924 UniqueConstraint('repo_id', 'revision', 'version'),
1924 UniqueConstraint('repo_id', 'revision', 'version'),
1925 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1925 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1926 'mysql_charset': 'utf8'}
1926 'mysql_charset': 'utf8'}
1927 )
1927 )
1928 STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed'
1928 STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed'
1929 STATUS_APPROVED = 'approved'
1929 STATUS_APPROVED = 'approved'
1930 STATUS_REJECTED = 'rejected'
1930 STATUS_REJECTED = 'rejected'
1931 STATUS_UNDER_REVIEW = 'under_review'
1931 STATUS_UNDER_REVIEW = 'under_review'
1932
1932
1933 STATUSES = [
1933 STATUSES = [
1934 (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default
1934 (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default
1935 (STATUS_APPROVED, _("Approved")),
1935 (STATUS_APPROVED, _("Approved")),
1936 (STATUS_REJECTED, _("Rejected")),
1936 (STATUS_REJECTED, _("Rejected")),
1937 (STATUS_UNDER_REVIEW, _("Under Review")),
1937 (STATUS_UNDER_REVIEW, _("Under Review")),
1938 ]
1938 ]
1939
1939
1940 changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True)
1940 changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True)
1941 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1941 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1942 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1942 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1943 revision = Column('revision', String(40), nullable=False)
1943 revision = Column('revision', String(40), nullable=False)
1944 status = Column('status', String(128), nullable=False, default=DEFAULT)
1944 status = Column('status', String(128), nullable=False, default=DEFAULT)
1945 changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id'))
1945 changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id'))
1946 modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
1946 modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
1947 version = Column('version', Integer(), nullable=False, default=0)
1947 version = Column('version', Integer(), nullable=False, default=0)
1948 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
1948 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
1949
1949
1950 author = relationship('User', lazy='joined')
1950 author = relationship('User', lazy='joined')
1951 repo = relationship('Repository')
1951 repo = relationship('Repository')
1952 comment = relationship('ChangesetComment', lazy='joined')
1952 comment = relationship('ChangesetComment', lazy='joined')
1953 pull_request = relationship('PullRequest', lazy='joined')
1953 pull_request = relationship('PullRequest', lazy='joined')
1954
1954
1955 def __unicode__(self):
1955 def __unicode__(self):
1956 return u"<%s('%s:%s')>" % (
1956 return u"<%s('%s:%s')>" % (
1957 self.__class__.__name__,
1957 self.__class__.__name__,
1958 self.status, self.author
1958 self.status, self.author
1959 )
1959 )
1960
1960
1961 @classmethod
1961 @classmethod
1962 def get_status_lbl(cls, value):
1962 def get_status_lbl(cls, value):
1963 return dict(cls.STATUSES).get(value)
1963 return dict(cls.STATUSES).get(value)
1964
1964
1965 @property
1965 @property
1966 def status_lbl(self):
1966 def status_lbl(self):
1967 return ChangesetStatus.get_status_lbl(self.status)
1967 return ChangesetStatus.get_status_lbl(self.status)
1968
1968
1969
1969
1970 class PullRequest(Base, BaseModel):
1970 class PullRequest(Base, BaseModel):
1971 __tablename__ = 'pull_requests'
1971 __tablename__ = 'pull_requests'
1972 __table_args__ = (
1972 __table_args__ = (
1973 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1973 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1974 'mysql_charset': 'utf8'},
1974 'mysql_charset': 'utf8'},
1975 )
1975 )
1976
1976
1977 STATUS_NEW = u'new'
1977 STATUS_NEW = u'new'
1978 STATUS_OPEN = u'open'
1978 STATUS_OPEN = u'open'
1979 STATUS_CLOSED = u'closed'
1979 STATUS_CLOSED = u'closed'
1980
1980
1981 pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True)
1981 pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True)
1982 title = Column('title', Unicode(256), nullable=True)
1982 title = Column('title', Unicode(256), nullable=True)
1983 description = Column('description', UnicodeText(10240), nullable=True)
1983 description = Column('description', UnicodeText(10240), nullable=True)
1984 status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW)
1984 status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW)
1985 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1985 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1986 updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1986 updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1987 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1987 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1988 _revisions = Column('revisions', UnicodeText(20500)) # 500 revisions max
1988 _revisions = Column('revisions', UnicodeText(20500)) # 500 revisions max
1989 org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1989 org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1990 org_ref = Column('org_ref', Unicode(256), nullable=False)
1990 org_ref = Column('org_ref', Unicode(256), nullable=False)
1991 other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1991 other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1992 other_ref = Column('other_ref', Unicode(256), nullable=False)
1992 other_ref = Column('other_ref', Unicode(256), nullable=False)
1993
1993
1994 @hybrid_property
1994 @hybrid_property
1995 def revisions(self):
1995 def revisions(self):
1996 return self._revisions.split(':')
1996 return self._revisions.split(':')
1997
1997
1998 @revisions.setter
1998 @revisions.setter
1999 def revisions(self, val):
1999 def revisions(self, val):
2000 self._revisions = ':'.join(val)
2000 self._revisions = ':'.join(val)
2001
2001
2002 @property
2002 @property
2003 def org_ref_parts(self):
2003 def org_ref_parts(self):
2004 return self.org_ref.split(':')
2004 return self.org_ref.split(':')
2005
2005
2006 @property
2006 @property
2007 def other_ref_parts(self):
2007 def other_ref_parts(self):
2008 return self.other_ref.split(':')
2008 return self.other_ref.split(':')
2009
2009
2010 author = relationship('User', lazy='joined')
2010 author = relationship('User', lazy='joined')
2011 reviewers = relationship('PullRequestReviewers',
2011 reviewers = relationship('PullRequestReviewers',
2012 cascade="all, delete, delete-orphan")
2012 cascade="all, delete, delete-orphan")
2013 org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id')
2013 org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id')
2014 other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id')
2014 other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id')
2015 statuses = relationship('ChangesetStatus')
2015 statuses = relationship('ChangesetStatus')
2016 comments = relationship('ChangesetComment',
2016 comments = relationship('ChangesetComment',
2017 cascade="all, delete, delete-orphan")
2017 cascade="all, delete, delete-orphan")
2018
2018
2019 def is_closed(self):
2019 def is_closed(self):
2020 return self.status == self.STATUS_CLOSED
2020 return self.status == self.STATUS_CLOSED
2021
2021
2022 @property
2022 @property
2023 def last_review_status(self):
2023 def last_review_status(self):
2024 return self.statuses[-1].status if self.statuses else ''
2024 return self.statuses[-1].status if self.statuses else ''
2025
2025
2026 def __json__(self):
2026 def __json__(self):
2027 return dict(
2027 return dict(
2028 revisions=self.revisions
2028 revisions=self.revisions
2029 )
2029 )
2030
2030
2031
2031
2032 class PullRequestReviewers(Base, BaseModel):
2032 class PullRequestReviewers(Base, BaseModel):
2033 __tablename__ = 'pull_request_reviewers'
2033 __tablename__ = 'pull_request_reviewers'
2034 __table_args__ = (
2034 __table_args__ = (
2035 {'extend_existing': True, 'mysql_engine': 'InnoDB',
2035 {'extend_existing': True, 'mysql_engine': 'InnoDB',
2036 'mysql_charset': 'utf8'},
2036 'mysql_charset': 'utf8'},
2037 )
2037 )
2038
2038
2039 def __init__(self, user=None, pull_request=None):
2039 def __init__(self, user=None, pull_request=None):
2040 self.user = user
2040 self.user = user
2041 self.pull_request = pull_request
2041 self.pull_request = pull_request
2042
2042
2043 pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True)
2043 pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True)
2044 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False)
2044 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False)
2045 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True)
2045 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True)
2046
2046
2047 user = relationship('User')
2047 user = relationship('User')
2048 pull_request = relationship('PullRequest')
2048 pull_request = relationship('PullRequest')
2049
2049
2050
2050
2051 class Notification(Base, BaseModel):
2051 class Notification(Base, BaseModel):
2052 __tablename__ = 'notifications'
2052 __tablename__ = 'notifications'
2053 __table_args__ = (
2053 __table_args__ = (
2054 Index('notification_type_idx', 'type'),
2054 Index('notification_type_idx', 'type'),
2055 {'extend_existing': True, 'mysql_engine': 'InnoDB',
2055 {'extend_existing': True, 'mysql_engine': 'InnoDB',
2056 'mysql_charset': 'utf8'},
2056 'mysql_charset': 'utf8'},
2057 )
2057 )
2058
2058
2059 TYPE_CHANGESET_COMMENT = u'cs_comment'
2059 TYPE_CHANGESET_COMMENT = u'cs_comment'
2060 TYPE_MESSAGE = u'message'
2060 TYPE_MESSAGE = u'message'
2061 TYPE_MENTION = u'mention'
2061 TYPE_MENTION = u'mention'
2062 TYPE_REGISTRATION = u'registration'
2062 TYPE_REGISTRATION = u'registration'
2063 TYPE_PULL_REQUEST = u'pull_request'
2063 TYPE_PULL_REQUEST = u'pull_request'
2064 TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment'
2064 TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment'
2065
2065
2066 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
2066 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
2067 subject = Column('subject', Unicode(512), nullable=True)
2067 subject = Column('subject', Unicode(512), nullable=True)
2068 body = Column('body', UnicodeText(50000), nullable=True)
2068 body = Column('body', UnicodeText(50000), nullable=True)
2069 created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
2069 created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
2070 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
2070 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
2071 type_ = Column('type', Unicode(256))
2071 type_ = Column('type', Unicode(256))
2072
2072
2073 created_by_user = relationship('User')
2073 created_by_user = relationship('User')
2074 notifications_to_users = relationship('UserNotification', lazy='joined',
2074 notifications_to_users = relationship('UserNotification', lazy='joined',
2075 cascade="all, delete, delete-orphan")
2075 cascade="all, delete, delete-orphan")
2076
2076
2077 @property
2077 @property
2078 def recipients(self):
2078 def recipients(self):
2079 return [x.user for x in UserNotification.query()\
2079 return [x.user for x in UserNotification.query()\
2080 .filter(UserNotification.notification == self)\
2080 .filter(UserNotification.notification == self)\
2081 .order_by(UserNotification.user_id.asc()).all()]
2081 .order_by(UserNotification.user_id.asc()).all()]
2082
2082
2083 @classmethod
2083 @classmethod
2084 def create(cls, created_by, subject, body, recipients, type_=None):
2084 def create(cls, created_by, subject, body, recipients, type_=None):
2085 if type_ is None:
2085 if type_ is None:
2086 type_ = Notification.TYPE_MESSAGE
2086 type_ = Notification.TYPE_MESSAGE
2087
2087
2088 notification = cls()
2088 notification = cls()
2089 notification.created_by_user = created_by
2089 notification.created_by_user = created_by
2090 notification.subject = subject
2090 notification.subject = subject
2091 notification.body = body
2091 notification.body = body
2092 notification.type_ = type_
2092 notification.type_ = type_
2093 notification.created_on = datetime.datetime.now()
2093 notification.created_on = datetime.datetime.now()
2094
2094
2095 for u in recipients:
2095 for u in recipients:
2096 assoc = UserNotification()
2096 assoc = UserNotification()
2097 assoc.notification = notification
2097 assoc.notification = notification
2098 u.notifications.append(assoc)
2098 u.notifications.append(assoc)
2099 Session().add(notification)
2099 Session().add(notification)
2100 return notification
2100 return notification
2101
2101
2102 @property
2102 @property
2103 def description(self):
2103 def description(self):
2104 from rhodecode.model.notification import NotificationModel
2104 from rhodecode.model.notification import NotificationModel
2105 return NotificationModel().make_description(self)
2105 return NotificationModel().make_description(self)
2106
2106
2107
2107
2108 class UserNotification(Base, BaseModel):
2108 class UserNotification(Base, BaseModel):
2109 __tablename__ = 'user_to_notification'
2109 __tablename__ = 'user_to_notification'
2110 __table_args__ = (
2110 __table_args__ = (
2111 UniqueConstraint('user_id', 'notification_id'),
2111 UniqueConstraint('user_id', 'notification_id'),
2112 {'extend_existing': True, 'mysql_engine': 'InnoDB',
2112 {'extend_existing': True, 'mysql_engine': 'InnoDB',
2113 'mysql_charset': 'utf8'}
2113 'mysql_charset': 'utf8'}
2114 )
2114 )
2115 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
2115 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
2116 notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
2116 notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
2117 read = Column('read', Boolean, default=False)
2117 read = Column('read', Boolean, default=False)
2118 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
2118 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
2119
2119
2120 user = relationship('User', lazy="joined")
2120 user = relationship('User', lazy="joined")
2121 notification = relationship('Notification', lazy="joined",
2121 notification = relationship('Notification', lazy="joined",
2122 order_by=lambda: Notification.created_on.desc(),)
2122 order_by=lambda: Notification.created_on.desc(),)
2123
2123
2124 def mark_as_read(self):
2124 def mark_as_read(self):
2125 self.read = True
2125 self.read = True
2126 Session().add(self)
2126 Session().add(self)
2127
2127
2128
2128
2129 class Gist(Base, BaseModel):
2129 class Gist(Base, BaseModel):
2130 __tablename__ = 'gists'
2130 __tablename__ = 'gists'
2131 __table_args__ = (
2131 __table_args__ = (
2132 Index('g_gist_access_id_idx', 'gist_access_id'),
2132 Index('g_gist_access_id_idx', 'gist_access_id'),
2133 Index('g_created_on_idx', 'created_on'),
2133 Index('g_created_on_idx', 'created_on'),
2134 {'extend_existing': True, 'mysql_engine': 'InnoDB',
2134 {'extend_existing': True, 'mysql_engine': 'InnoDB',
2135 'mysql_charset': 'utf8'}
2135 'mysql_charset': 'utf8'}
2136 )
2136 )
2137 GIST_PUBLIC = u'public'
2137 GIST_PUBLIC = u'public'
2138 GIST_PRIVATE = u'private'
2138 GIST_PRIVATE = u'private'
2139
2139
2140 gist_id = Column('gist_id', Integer(), primary_key=True)
2140 gist_id = Column('gist_id', Integer(), primary_key=True)
2141 gist_access_id = Column('gist_access_id', UnicodeText(1024))
2141 gist_access_id = Column('gist_access_id', Unicode(1024))
2142 gist_description = Column('gist_description', UnicodeText(1024))
2142 gist_description = Column('gist_description', UnicodeText(1024))
2143 gist_owner = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=True)
2143 gist_owner = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=True)
2144 gist_expires = Column('gist_expires', Float(), nullable=False)
2144 gist_expires = Column('gist_expires', Float(), nullable=False)
2145 gist_type = Column('gist_type', Unicode(128), nullable=False)
2145 gist_type = Column('gist_type', Unicode(128), nullable=False)
2146 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
2146 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
2147 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
2147 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
2148
2148
2149 owner = relationship('User')
2149 owner = relationship('User')
2150
2150
2151 @classmethod
2151 @classmethod
2152 def get_or_404(cls, id_):
2152 def get_or_404(cls, id_):
2153 res = cls.query().filter(cls.gist_access_id == id_).scalar()
2153 res = cls.query().filter(cls.gist_access_id == id_).scalar()
2154 if not res:
2154 if not res:
2155 raise HTTPNotFound
2155 raise HTTPNotFound
2156 return res
2156 return res
2157
2157
2158 @classmethod
2158 @classmethod
2159 def get_by_access_id(cls, gist_access_id):
2159 def get_by_access_id(cls, gist_access_id):
2160 return cls.query().filter(cls.gist_access_id == gist_access_id).scalar()
2160 return cls.query().filter(cls.gist_access_id == gist_access_id).scalar()
2161
2161
2162 def gist_url(self):
2162 def gist_url(self):
2163 import rhodecode
2163 import rhodecode
2164 alias_url = rhodecode.CONFIG.get('gist_alias_url')
2164 alias_url = rhodecode.CONFIG.get('gist_alias_url')
2165 if alias_url:
2165 if alias_url:
2166 return alias_url.replace('{gistid}', self.gist_access_id)
2166 return alias_url.replace('{gistid}', self.gist_access_id)
2167
2167
2168 from pylons import url
2168 from pylons import url
2169 return url('gist', gist_id=self.gist_access_id, qualified=True)
2169 return url('gist', gist_id=self.gist_access_id, qualified=True)
2170
2170
2171 @classmethod
2171 @classmethod
2172 def base_path(cls):
2172 def base_path(cls):
2173 """
2173 """
2174 Returns base path when all gists are stored
2174 Returns base path when all gists are stored
2175
2175
2176 :param cls:
2176 :param cls:
2177 """
2177 """
2178 from rhodecode.model.gist import GIST_STORE_LOC
2178 from rhodecode.model.gist import GIST_STORE_LOC
2179 q = Session().query(RhodeCodeUi)\
2179 q = Session().query(RhodeCodeUi)\
2180 .filter(RhodeCodeUi.ui_key == URL_SEP)
2180 .filter(RhodeCodeUi.ui_key == URL_SEP)
2181 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
2181 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
2182 return os.path.join(q.one().ui_value, GIST_STORE_LOC)
2182 return os.path.join(q.one().ui_value, GIST_STORE_LOC)
2183
2183
2184 def get_api_data(self):
2184 def get_api_data(self):
2185 """
2185 """
2186 Common function for generating gist related data for API
2186 Common function for generating gist related data for API
2187 """
2187 """
2188 gist = self
2188 gist = self
2189 data = dict(
2189 data = dict(
2190 gist_id=gist.gist_id,
2190 gist_id=gist.gist_id,
2191 type=gist.gist_type,
2191 type=gist.gist_type,
2192 access_id=gist.gist_access_id,
2192 access_id=gist.gist_access_id,
2193 description=gist.gist_description,
2193 description=gist.gist_description,
2194 url=gist.gist_url(),
2194 url=gist.gist_url(),
2195 expires=gist.gist_expires,
2195 expires=gist.gist_expires,
2196 created_on=gist.created_on,
2196 created_on=gist.created_on,
2197 )
2197 )
2198 return data
2198 return data
2199
2199
2200 def __json__(self):
2200 def __json__(self):
2201 data = dict(
2201 data = dict(
2202 )
2202 )
2203 data.update(self.get_api_data())
2203 data.update(self.get_api_data())
2204 return data
2204 return data
2205 ## SCM functions
2205 ## SCM functions
2206
2206
2207 @property
2207 @property
2208 def scm_instance(self):
2208 def scm_instance(self):
2209 from rhodecode.lib.vcs import get_repo
2209 from rhodecode.lib.vcs import get_repo
2210 base_path = self.base_path()
2210 base_path = self.base_path()
2211 return get_repo(os.path.join(*map(safe_str,
2211 return get_repo(os.path.join(*map(safe_str,
2212 [base_path, self.gist_access_id])))
2212 [base_path, self.gist_access_id])))
2213
2213
2214
2214
2215 class DbMigrateVersion(Base, BaseModel):
2215 class DbMigrateVersion(Base, BaseModel):
2216 __tablename__ = 'db_migrate_version'
2216 __tablename__ = 'db_migrate_version'
2217 __table_args__ = (
2217 __table_args__ = (
2218 {'extend_existing': True, 'mysql_engine': 'InnoDB',
2218 {'extend_existing': True, 'mysql_engine': 'InnoDB',
2219 'mysql_charset': 'utf8'},
2219 'mysql_charset': 'utf8'},
2220 )
2220 )
2221 repository_id = Column('repository_id', String(250), primary_key=True)
2221 repository_id = Column('repository_id', String(250), primary_key=True)
2222 repository_path = Column('repository_path', Text)
2222 repository_path = Column('repository_path', Text)
2223 version = Column('version', Integer)
2223 version = Column('version', Integer)
General Comments 0
You need to be logged in to leave comments. Login now