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