##// END OF EJS Templates
fixed issue with hybrid property for ldap_active...
marcink -
r2013:8530c3cd beta
parent child Browse files
Show More
@@ -1,1185 +1,1198 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 logging
27 import logging
28 import datetime
28 import datetime
29 import traceback
29 import traceback
30 from collections import defaultdict
30 from collections import defaultdict
31
31
32 from sqlalchemy import *
32 from sqlalchemy import *
33 from sqlalchemy.ext.hybrid import hybrid_property
33 from sqlalchemy.ext.hybrid import hybrid_property
34 from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
34 from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
35 from beaker.cache import cache_region, region_invalidate
35 from beaker.cache import cache_region, region_invalidate
36
36
37 from rhodecode.lib.vcs import get_backend
37 from rhodecode.lib.vcs import get_backend
38 from rhodecode.lib.vcs.utils.helpers import get_scm
38 from rhodecode.lib.vcs.utils.helpers import get_scm
39 from rhodecode.lib.vcs.exceptions import VCSError
39 from rhodecode.lib.vcs.exceptions import VCSError
40 from rhodecode.lib.vcs.utils.lazy import LazyProperty
40 from rhodecode.lib.vcs.utils.lazy import LazyProperty
41
41
42 from rhodecode.lib import str2bool, safe_str, get_changeset_safe, safe_unicode
42 from rhodecode.lib import str2bool, safe_str, get_changeset_safe, safe_unicode
43 from rhodecode.lib.compat import json
43 from rhodecode.lib.compat import json
44 from rhodecode.lib.caching_query import FromCache
44 from rhodecode.lib.caching_query import FromCache
45
45
46 from rhodecode.model.meta import Base, Session
46 from rhodecode.model.meta import Base, Session
47
47
48
48
49 log = logging.getLogger(__name__)
49 log = logging.getLogger(__name__)
50
50
51 #==============================================================================
51 #==============================================================================
52 # BASE CLASSES
52 # BASE CLASSES
53 #==============================================================================
53 #==============================================================================
54
54
55
55
56 class ModelSerializer(json.JSONEncoder):
56 class ModelSerializer(json.JSONEncoder):
57 """
57 """
58 Simple Serializer for JSON,
58 Simple Serializer for JSON,
59
59
60 usage::
60 usage::
61
61
62 to make object customized for serialization implement a __json__
62 to make object customized for serialization implement a __json__
63 method that will return a dict for serialization into json
63 method that will return a dict for serialization into json
64
64
65 example::
65 example::
66
66
67 class Task(object):
67 class Task(object):
68
68
69 def __init__(self, name, value):
69 def __init__(self, name, value):
70 self.name = name
70 self.name = name
71 self.value = value
71 self.value = value
72
72
73 def __json__(self):
73 def __json__(self):
74 return dict(name=self.name,
74 return dict(name=self.name,
75 value=self.value)
75 value=self.value)
76
76
77 """
77 """
78
78
79 def default(self, obj):
79 def default(self, obj):
80
80
81 if hasattr(obj, '__json__'):
81 if hasattr(obj, '__json__'):
82 return obj.__json__()
82 return obj.__json__()
83 else:
83 else:
84 return json.JSONEncoder.default(self, obj)
84 return json.JSONEncoder.default(self, obj)
85
85
86
86
87 class BaseModel(object):
87 class BaseModel(object):
88 """
88 """
89 Base Model for all classess
89 Base Model for all classess
90 """
90 """
91
91
92 @classmethod
92 @classmethod
93 def _get_keys(cls):
93 def _get_keys(cls):
94 """return column names for this model """
94 """return column names for this model """
95 return class_mapper(cls).c.keys()
95 return class_mapper(cls).c.keys()
96
96
97 def get_dict(self):
97 def get_dict(self):
98 """
98 """
99 return dict with keys and values corresponding
99 return dict with keys and values corresponding
100 to this model data """
100 to this model data """
101
101
102 d = {}
102 d = {}
103 for k in self._get_keys():
103 for k in self._get_keys():
104 d[k] = getattr(self, k)
104 d[k] = getattr(self, k)
105
105
106 # also use __json__() if present to get additional fields
106 # also use __json__() if present to get additional fields
107 for k, val in getattr(self, '__json__', lambda: {})().iteritems():
107 for k, val in getattr(self, '__json__', lambda: {})().iteritems():
108 d[k] = val
108 d[k] = val
109 return d
109 return d
110
110
111 def get_appstruct(self):
111 def get_appstruct(self):
112 """return list with keys and values tupples corresponding
112 """return list with keys and values tupples corresponding
113 to this model data """
113 to this model data """
114
114
115 l = []
115 l = []
116 for k in self._get_keys():
116 for k in self._get_keys():
117 l.append((k, getattr(self, k),))
117 l.append((k, getattr(self, k),))
118 return l
118 return l
119
119
120 def populate_obj(self, populate_dict):
120 def populate_obj(self, populate_dict):
121 """populate model with data from given populate_dict"""
121 """populate model with data from given populate_dict"""
122
122
123 for k in self._get_keys():
123 for k in self._get_keys():
124 if k in populate_dict:
124 if k in populate_dict:
125 setattr(self, k, populate_dict[k])
125 setattr(self, k, populate_dict[k])
126
126
127 @classmethod
127 @classmethod
128 def query(cls):
128 def query(cls):
129 return Session.query(cls)
129 return Session.query(cls)
130
130
131 @classmethod
131 @classmethod
132 def get(cls, id_):
132 def get(cls, id_):
133 if id_:
133 if id_:
134 return cls.query().get(id_)
134 return cls.query().get(id_)
135
135
136 @classmethod
136 @classmethod
137 def getAll(cls):
137 def getAll(cls):
138 return cls.query().all()
138 return cls.query().all()
139
139
140 @classmethod
140 @classmethod
141 def delete(cls, id_):
141 def delete(cls, id_):
142 obj = cls.query().get(id_)
142 obj = cls.query().get(id_)
143 Session.delete(obj)
143 Session.delete(obj)
144
144
145
145
146 class RhodeCodeSetting(Base, BaseModel):
146 class RhodeCodeSetting(Base, BaseModel):
147 __tablename__ = 'rhodecode_settings'
147 __tablename__ = 'rhodecode_settings'
148 __table_args__ = (
148 __table_args__ = (
149 UniqueConstraint('app_settings_name'),
149 UniqueConstraint('app_settings_name'),
150 {'extend_existing': True}
150 {'extend_existing': True}
151 )
151 )
152 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
152 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
153 app_settings_name = Column("app_settings_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
153 app_settings_name = Column("app_settings_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
154 _app_settings_value = Column("app_settings_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
154 _app_settings_value = Column("app_settings_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
155
155
156 def __init__(self, k='', v=''):
156 def __init__(self, k='', v=''):
157 self.app_settings_name = k
157 self.app_settings_name = k
158 self.app_settings_value = v
158 self.app_settings_value = v
159
159
160 @validates('_app_settings_value')
160 @validates('_app_settings_value')
161 def validate_settings_value(self, key, val):
161 def validate_settings_value(self, key, val):
162 assert type(val) == unicode
162 assert type(val) == unicode
163 return val
163 return val
164
164
165 @hybrid_property
165 @hybrid_property
166 def app_settings_value(self):
166 def app_settings_value(self):
167 v = self._app_settings_value
167 v = self._app_settings_value
168 if v == 'ldap_active':
168 if self.app_settings_name == 'ldap_active':
169 v = str2bool(v)
169 v = str2bool(v)
170 return v
170 return v
171
171
172 @app_settings_value.setter
172 @app_settings_value.setter
173 def app_settings_value(self, val):
173 def app_settings_value(self, val):
174 """
174 """
175 Setter that will always make sure we use unicode in app_settings_value
175 Setter that will always make sure we use unicode in app_settings_value
176
176
177 :param val:
177 :param val:
178 """
178 """
179 self._app_settings_value = safe_unicode(val)
179 self._app_settings_value = safe_unicode(val)
180
180
181 def __repr__(self):
181 def __repr__(self):
182 return "<%s('%s:%s')>" % (
182 return "<%s('%s:%s')>" % (
183 self.__class__.__name__,
183 self.__class__.__name__,
184 self.app_settings_name, self.app_settings_value
184 self.app_settings_name, self.app_settings_value
185 )
185 )
186
186
187 @classmethod
187 @classmethod
188 def get_by_name(cls, ldap_key):
188 def get_by_name(cls, ldap_key):
189 return cls.query()\
189 return cls.query()\
190 .filter(cls.app_settings_name == ldap_key).scalar()
190 .filter(cls.app_settings_name == ldap_key).scalar()
191
191
192 @classmethod
192 @classmethod
193 def get_app_settings(cls, cache=False):
193 def get_app_settings(cls, cache=False):
194
194
195 ret = cls.query()
195 ret = cls.query()
196
196
197 if cache:
197 if cache:
198 ret = ret.options(FromCache("sql_cache_short", "get_hg_settings"))
198 ret = ret.options(FromCache("sql_cache_short", "get_hg_settings"))
199
199
200 if not ret:
200 if not ret:
201 raise Exception('Could not get application settings !')
201 raise Exception('Could not get application settings !')
202 settings = {}
202 settings = {}
203 for each in ret:
203 for each in ret:
204 settings['rhodecode_' + each.app_settings_name] = \
204 settings['rhodecode_' + each.app_settings_name] = \
205 each.app_settings_value
205 each.app_settings_value
206
206
207 return settings
207 return settings
208
208
209 @classmethod
209 @classmethod
210 def get_ldap_settings(cls, cache=False):
210 def get_ldap_settings(cls, cache=False):
211 ret = cls.query()\
211 ret = cls.query()\
212 .filter(cls.app_settings_name.startswith('ldap_')).all()
212 .filter(cls.app_settings_name.startswith('ldap_')).all()
213 fd = {}
213 fd = {}
214 for row in ret:
214 for row in ret:
215 fd.update({row.app_settings_name:row.app_settings_value})
215 fd.update({row.app_settings_name:row.app_settings_value})
216
216
217 return fd
217 return fd
218
218
219
219
220 class RhodeCodeUi(Base, BaseModel):
220 class RhodeCodeUi(Base, BaseModel):
221 __tablename__ = 'rhodecode_ui'
221 __tablename__ = 'rhodecode_ui'
222 __table_args__ = (
222 __table_args__ = (
223 UniqueConstraint('ui_key'),
223 UniqueConstraint('ui_key'),
224 {'extend_existing': True}
224 {'extend_existing': True}
225 )
225 )
226
226
227 HOOK_UPDATE = 'changegroup.update'
227 HOOK_UPDATE = 'changegroup.update'
228 HOOK_REPO_SIZE = 'changegroup.repo_size'
228 HOOK_REPO_SIZE = 'changegroup.repo_size'
229 HOOK_PUSH = 'pretxnchangegroup.push_logger'
229 HOOK_PUSH = 'pretxnchangegroup.push_logger'
230 HOOK_PULL = 'preoutgoing.pull_logger'
230 HOOK_PULL = 'preoutgoing.pull_logger'
231
231
232 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
232 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
233 ui_section = Column("ui_section", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
233 ui_section = Column("ui_section", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
234 ui_key = Column("ui_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
234 ui_key = Column("ui_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
235 ui_value = Column("ui_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
235 ui_value = Column("ui_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
236 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
236 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
237
237
238 @classmethod
238 @classmethod
239 def get_by_key(cls, key):
239 def get_by_key(cls, key):
240 return cls.query().filter(cls.ui_key == key)
240 return cls.query().filter(cls.ui_key == key)
241
241
242 @classmethod
242 @classmethod
243 def get_builtin_hooks(cls):
243 def get_builtin_hooks(cls):
244 q = cls.query()
244 q = cls.query()
245 q = q.filter(cls.ui_key.in_([cls.HOOK_UPDATE,
245 q = q.filter(cls.ui_key.in_([cls.HOOK_UPDATE,
246 cls.HOOK_REPO_SIZE,
246 cls.HOOK_REPO_SIZE,
247 cls.HOOK_PUSH, cls.HOOK_PULL]))
247 cls.HOOK_PUSH, cls.HOOK_PULL]))
248 return q.all()
248 return q.all()
249
249
250 @classmethod
250 @classmethod
251 def get_custom_hooks(cls):
251 def get_custom_hooks(cls):
252 q = cls.query()
252 q = cls.query()
253 q = q.filter(~cls.ui_key.in_([cls.HOOK_UPDATE,
253 q = q.filter(~cls.ui_key.in_([cls.HOOK_UPDATE,
254 cls.HOOK_REPO_SIZE,
254 cls.HOOK_REPO_SIZE,
255 cls.HOOK_PUSH, cls.HOOK_PULL]))
255 cls.HOOK_PUSH, cls.HOOK_PULL]))
256 q = q.filter(cls.ui_section == 'hooks')
256 q = q.filter(cls.ui_section == 'hooks')
257 return q.all()
257 return q.all()
258
258
259 @classmethod
259 @classmethod
260 def create_or_update_hook(cls, key, val):
260 def create_or_update_hook(cls, key, val):
261 new_ui = cls.get_by_key(key).scalar() or cls()
261 new_ui = cls.get_by_key(key).scalar() or cls()
262 new_ui.ui_section = 'hooks'
262 new_ui.ui_section = 'hooks'
263 new_ui.ui_active = True
263 new_ui.ui_active = True
264 new_ui.ui_key = key
264 new_ui.ui_key = key
265 new_ui.ui_value = val
265 new_ui.ui_value = val
266
266
267 Session.add(new_ui)
267 Session.add(new_ui)
268
268
269
269
270 class User(Base, BaseModel):
270 class User(Base, BaseModel):
271 __tablename__ = 'users'
271 __tablename__ = 'users'
272 __table_args__ = (
272 __table_args__ = (
273 UniqueConstraint('username'), UniqueConstraint('email'),
273 UniqueConstraint('username'), UniqueConstraint('email'),
274 {'extend_existing': True}
274 {'extend_existing': True}
275 )
275 )
276 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
276 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
277 username = Column("username", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
277 username = Column("username", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
278 password = Column("password", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
278 password = Column("password", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
279 active = Column("active", Boolean(), nullable=True, unique=None, default=None)
279 active = Column("active", Boolean(), nullable=True, unique=None, default=None)
280 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
280 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
281 name = Column("name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
281 name = Column("name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
282 lastname = Column("lastname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
282 lastname = Column("lastname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
283 _email = Column("email", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
283 _email = Column("email", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
284 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
284 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
285 ldap_dn = Column("ldap_dn", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
285 ldap_dn = Column("ldap_dn", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
286 api_key = Column("api_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
286 api_key = Column("api_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
287
287
288 user_log = relationship('UserLog', cascade='all')
288 user_log = relationship('UserLog', cascade='all')
289 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
289 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
290
290
291 repositories = relationship('Repository')
291 repositories = relationship('Repository')
292 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
292 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
293 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
293 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
294
294
295 group_member = relationship('UsersGroupMember', cascade='all')
295 group_member = relationship('UsersGroupMember', cascade='all')
296
296
297 notifications = relationship('UserNotification',)
297 notifications = relationship('UserNotification',)
298
298
299 @hybrid_property
299 @hybrid_property
300 def email(self):
300 def email(self):
301 return self._email
301 return self._email
302
302
303 @email.setter
303 @email.setter
304 def email(self, val):
304 def email(self, val):
305 self._email = val.lower() if val else None
305 self._email = val.lower() if val else None
306
306
307 @property
307 @property
308 def full_name(self):
308 def full_name(self):
309 return '%s %s' % (self.name, self.lastname)
309 return '%s %s' % (self.name, self.lastname)
310
310
311 @property
311 @property
312 def full_name_or_username(self):
312 def full_name_or_username(self):
313 return ('%s %s' % (self.name, self.lastname)
313 return ('%s %s' % (self.name, self.lastname)
314 if (self.name and self.lastname) else self.username)
314 if (self.name and self.lastname) else self.username)
315
315
316 @property
316 @property
317 def full_contact(self):
317 def full_contact(self):
318 return '%s %s <%s>' % (self.name, self.lastname, self.email)
318 return '%s %s <%s>' % (self.name, self.lastname, self.email)
319
319
320 @property
320 @property
321 def short_contact(self):
321 def short_contact(self):
322 return '%s %s' % (self.name, self.lastname)
322 return '%s %s' % (self.name, self.lastname)
323
323
324 @property
324 @property
325 def is_admin(self):
325 def is_admin(self):
326 return self.admin
326 return self.admin
327
327
328 def __repr__(self):
328 def __repr__(self):
329 return "<%s('id:%s:%s')>" % (self.__class__.__name__,
329 return "<%s('id:%s:%s')>" % (self.__class__.__name__,
330 self.user_id, self.username)
330 self.user_id, self.username)
331
331
332 @classmethod
332 @classmethod
333 def get_by_username(cls, username, case_insensitive=False, cache=False):
333 def get_by_username(cls, username, case_insensitive=False, cache=False):
334 if case_insensitive:
334 if case_insensitive:
335 q = cls.query().filter(cls.username.ilike(username))
335 q = cls.query().filter(cls.username.ilike(username))
336 else:
336 else:
337 q = cls.query().filter(cls.username == username)
337 q = cls.query().filter(cls.username == username)
338
338
339 if cache:
339 if cache:
340 q = q.options(FromCache("sql_cache_short",
340 q = q.options(FromCache("sql_cache_short",
341 "get_user_%s" % username))
341 "get_user_%s" % username))
342 return q.scalar()
342 return q.scalar()
343
343
344 @classmethod
344 @classmethod
345 def get_by_api_key(cls, api_key, cache=False):
345 def get_by_api_key(cls, api_key, cache=False):
346 q = cls.query().filter(cls.api_key == api_key)
346 q = cls.query().filter(cls.api_key == api_key)
347
347
348 if cache:
348 if cache:
349 q = q.options(FromCache("sql_cache_short",
349 q = q.options(FromCache("sql_cache_short",
350 "get_api_key_%s" % api_key))
350 "get_api_key_%s" % api_key))
351 return q.scalar()
351 return q.scalar()
352
352
353 @classmethod
353 @classmethod
354 def get_by_email(cls, email, case_insensitive=False, cache=False):
354 def get_by_email(cls, email, case_insensitive=False, cache=False):
355 if case_insensitive:
355 if case_insensitive:
356 q = cls.query().filter(cls.email.ilike(email))
356 q = cls.query().filter(cls.email.ilike(email))
357 else:
357 else:
358 q = cls.query().filter(cls.email == email)
358 q = cls.query().filter(cls.email == email)
359
359
360 if cache:
360 if cache:
361 q = q.options(FromCache("sql_cache_short",
361 q = q.options(FromCache("sql_cache_short",
362 "get_api_key_%s" % email))
362 "get_api_key_%s" % email))
363 return q.scalar()
363 return q.scalar()
364
364
365 def update_lastlogin(self):
365 def update_lastlogin(self):
366 """Update user lastlogin"""
366 """Update user lastlogin"""
367 self.last_login = datetime.datetime.now()
367 self.last_login = datetime.datetime.now()
368 Session.add(self)
368 Session.add(self)
369 log.debug('updated user %s lastlogin' % self.username)
369 log.debug('updated user %s lastlogin' % self.username)
370
370
371 def __json__(self):
371 def __json__(self):
372 return dict(
372 return dict(
373 email=self.email,
373 email=self.email,
374 full_name=self.full_name,
374 full_name=self.full_name,
375 full_name_or_username=self.full_name_or_username,
375 full_name_or_username=self.full_name_or_username,
376 short_contact=self.short_contact,
376 short_contact=self.short_contact,
377 full_contact=self.full_contact
377 full_contact=self.full_contact
378 )
378 )
379
379
380
380
381 class UserLog(Base, BaseModel):
381 class UserLog(Base, BaseModel):
382 __tablename__ = 'user_logs'
382 __tablename__ = 'user_logs'
383 __table_args__ = {'extend_existing': True}
383 __table_args__ = {'extend_existing': True}
384 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
384 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
385 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
385 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
386 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
386 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
387 repository_name = Column("repository_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
387 repository_name = Column("repository_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
388 user_ip = Column("user_ip", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
388 user_ip = Column("user_ip", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
389 action = Column("action", UnicodeText(length=1200000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
389 action = Column("action", UnicodeText(length=1200000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
390 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
390 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
391
391
392 @property
392 @property
393 def action_as_day(self):
393 def action_as_day(self):
394 return datetime.date(*self.action_date.timetuple()[:3])
394 return datetime.date(*self.action_date.timetuple()[:3])
395
395
396 user = relationship('User')
396 user = relationship('User')
397 repository = relationship('Repository',cascade='')
397 repository = relationship('Repository',cascade='')
398
398
399
399
400 class UsersGroup(Base, BaseModel):
400 class UsersGroup(Base, BaseModel):
401 __tablename__ = 'users_groups'
401 __tablename__ = 'users_groups'
402 __table_args__ = {'extend_existing': True}
402 __table_args__ = {'extend_existing': True}
403
403
404 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
404 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
405 users_group_name = Column("users_group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
405 users_group_name = Column("users_group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
406 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
406 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
407
407
408 members = relationship('UsersGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
408 members = relationship('UsersGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
409
409
410 def __repr__(self):
410 def __repr__(self):
411 return '<userGroup(%s)>' % (self.users_group_name)
411 return '<userGroup(%s)>' % (self.users_group_name)
412
412
413 @classmethod
413 @classmethod
414 def get_by_group_name(cls, group_name, cache=False,
414 def get_by_group_name(cls, group_name, cache=False,
415 case_insensitive=False):
415 case_insensitive=False):
416 if case_insensitive:
416 if case_insensitive:
417 q = cls.query().filter(cls.users_group_name.ilike(group_name))
417 q = cls.query().filter(cls.users_group_name.ilike(group_name))
418 else:
418 else:
419 q = cls.query().filter(cls.users_group_name == group_name)
419 q = cls.query().filter(cls.users_group_name == group_name)
420 if cache:
420 if cache:
421 q = q.options(FromCache("sql_cache_short",
421 q = q.options(FromCache("sql_cache_short",
422 "get_user_%s" % group_name))
422 "get_user_%s" % group_name))
423 return q.scalar()
423 return q.scalar()
424
424
425 @classmethod
425 @classmethod
426 def get(cls, users_group_id, cache=False):
426 def get(cls, users_group_id, cache=False):
427 users_group = cls.query()
427 users_group = cls.query()
428 if cache:
428 if cache:
429 users_group = users_group.options(FromCache("sql_cache_short",
429 users_group = users_group.options(FromCache("sql_cache_short",
430 "get_users_group_%s" % users_group_id))
430 "get_users_group_%s" % users_group_id))
431 return users_group.get(users_group_id)
431 return users_group.get(users_group_id)
432
432
433
433
434 class UsersGroupMember(Base, BaseModel):
434 class UsersGroupMember(Base, BaseModel):
435 __tablename__ = 'users_groups_members'
435 __tablename__ = 'users_groups_members'
436 __table_args__ = {'extend_existing': True}
436 __table_args__ = {'extend_existing': True}
437
437
438 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
438 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
439 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
439 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
440 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
440 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
441
441
442 user = relationship('User', lazy='joined')
442 user = relationship('User', lazy='joined')
443 users_group = relationship('UsersGroup')
443 users_group = relationship('UsersGroup')
444
444
445 def __init__(self, gr_id='', u_id=''):
445 def __init__(self, gr_id='', u_id=''):
446 self.users_group_id = gr_id
446 self.users_group_id = gr_id
447 self.user_id = u_id
447 self.user_id = u_id
448
448
449
449 class Repository(Base, BaseModel):
450 class Repository(Base, BaseModel):
450 __tablename__ = 'repositories'
451 __tablename__ = 'repositories'
451 __table_args__ = (
452 __table_args__ = (
452 UniqueConstraint('repo_name'),
453 UniqueConstraint('repo_name'),
453 {'extend_existing': True},
454 {'extend_existing': True},
454 )
455 )
455
456
456 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
457 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
457 repo_name = Column("repo_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
458 repo_name = Column("repo_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
458 clone_uri = Column("clone_uri", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
459 clone_uri = Column("clone_uri", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
459 repo_type = Column("repo_type", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default='hg')
460 repo_type = Column("repo_type", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default='hg')
460 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
461 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
461 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
462 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
462 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
463 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
463 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
464 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
464 description = Column("description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
465 description = Column("description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
465 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
466 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
466
467
467 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
468 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
468 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
469 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
469
470
470 user = relationship('User')
471 user = relationship('User')
471 fork = relationship('Repository', remote_side=repo_id)
472 fork = relationship('Repository', remote_side=repo_id)
472 group = relationship('RepoGroup')
473 group = relationship('RepoGroup')
473 repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
474 repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
474 users_group_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
475 users_group_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
475 stats = relationship('Statistics', cascade='all', uselist=False)
476 stats = relationship('Statistics', cascade='all', uselist=False)
476
477
477 followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all')
478 followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all')
478
479
479 logs = relationship('UserLog')
480 logs = relationship('UserLog')
480
481
481 def __repr__(self):
482 def __repr__(self):
482 return "<%s('%s:%s')>" % (self.__class__.__name__,
483 return "<%s('%s:%s')>" % (self.__class__.__name__,
483 self.repo_id, self.repo_name)
484 self.repo_id, self.repo_name)
484
485
485 @classmethod
486 @classmethod
486 def url_sep(cls):
487 def url_sep(cls):
487 return '/'
488 return '/'
488
489
489 @classmethod
490 @classmethod
490 def get_by_repo_name(cls, repo_name):
491 def get_by_repo_name(cls, repo_name):
491 q = Session.query(cls).filter(cls.repo_name == repo_name)
492 q = Session.query(cls).filter(cls.repo_name == repo_name)
492 q = q.options(joinedload(Repository.fork))\
493 q = q.options(joinedload(Repository.fork))\
493 .options(joinedload(Repository.user))\
494 .options(joinedload(Repository.user))\
494 .options(joinedload(Repository.group))
495 .options(joinedload(Repository.group))
495 return q.scalar()
496 return q.scalar()
496
497
497 @classmethod
498 @classmethod
498 def get_repo_forks(cls, repo_id):
499 def get_repo_forks(cls, repo_id):
499 return cls.query().filter(Repository.fork_id == repo_id)
500 return cls.query().filter(Repository.fork_id == repo_id)
500
501
501 @classmethod
502 @classmethod
502 def base_path(cls):
503 def base_path(cls):
503 """
504 """
504 Returns base path when all repos are stored
505 Returns base path when all repos are stored
505
506
506 :param cls:
507 :param cls:
507 """
508 """
508 q = Session.query(RhodeCodeUi)\
509 q = Session.query(RhodeCodeUi)\
509 .filter(RhodeCodeUi.ui_key == cls.url_sep())
510 .filter(RhodeCodeUi.ui_key == cls.url_sep())
510 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
511 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
511 return q.one().ui_value
512 return q.one().ui_value
512
513
513 @property
514 @property
514 def just_name(self):
515 def just_name(self):
515 return self.repo_name.split(Repository.url_sep())[-1]
516 return self.repo_name.split(Repository.url_sep())[-1]
516
517
517 @property
518 @property
518 def groups_with_parents(self):
519 def groups_with_parents(self):
519 groups = []
520 groups = []
520 if self.group is None:
521 if self.group is None:
521 return groups
522 return groups
522
523
523 cur_gr = self.group
524 cur_gr = self.group
524 groups.insert(0, cur_gr)
525 groups.insert(0, cur_gr)
525 while 1:
526 while 1:
526 gr = getattr(cur_gr, 'parent_group', None)
527 gr = getattr(cur_gr, 'parent_group', None)
527 cur_gr = cur_gr.parent_group
528 cur_gr = cur_gr.parent_group
528 if gr is None:
529 if gr is None:
529 break
530 break
530 groups.insert(0, gr)
531 groups.insert(0, gr)
531
532
532 return groups
533 return groups
533
534
534 @property
535 @property
535 def groups_and_repo(self):
536 def groups_and_repo(self):
536 return self.groups_with_parents, self.just_name
537 return self.groups_with_parents, self.just_name
537
538
538 @LazyProperty
539 @LazyProperty
539 def repo_path(self):
540 def repo_path(self):
540 """
541 """
541 Returns base full path for that repository means where it actually
542 Returns base full path for that repository means where it actually
542 exists on a filesystem
543 exists on a filesystem
543 """
544 """
544 q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key ==
545 q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key ==
545 Repository.url_sep())
546 Repository.url_sep())
546 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
547 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
547 return q.one().ui_value
548 return q.one().ui_value
548
549
549 @property
550 @property
550 def repo_full_path(self):
551 def repo_full_path(self):
551 p = [self.repo_path]
552 p = [self.repo_path]
552 # we need to split the name by / since this is how we store the
553 # we need to split the name by / since this is how we store the
553 # names in the database, but that eventually needs to be converted
554 # names in the database, but that eventually needs to be converted
554 # into a valid system path
555 # into a valid system path
555 p += self.repo_name.split(Repository.url_sep())
556 p += self.repo_name.split(Repository.url_sep())
556 return os.path.join(*p)
557 return os.path.join(*p)
557
558
558 def get_new_name(self, repo_name):
559 def get_new_name(self, repo_name):
559 """
560 """
560 returns new full repository name based on assigned group and new new
561 returns new full repository name based on assigned group and new new
561
562
562 :param group_name:
563 :param group_name:
563 """
564 """
564 path_prefix = self.group.full_path_splitted if self.group else []
565 path_prefix = self.group.full_path_splitted if self.group else []
565 return Repository.url_sep().join(path_prefix + [repo_name])
566 return Repository.url_sep().join(path_prefix + [repo_name])
566
567
567 @property
568 @property
568 def _ui(self):
569 def _ui(self):
569 """
570 """
570 Creates an db based ui object for this repository
571 Creates an db based ui object for this repository
571 """
572 """
572 from mercurial import ui
573 from mercurial import ui
573 from mercurial import config
574 from mercurial import config
574 baseui = ui.ui()
575 baseui = ui.ui()
575
576
576 #clean the baseui object
577 #clean the baseui object
577 baseui._ocfg = config.config()
578 baseui._ocfg = config.config()
578 baseui._ucfg = config.config()
579 baseui._ucfg = config.config()
579 baseui._tcfg = config.config()
580 baseui._tcfg = config.config()
580
581
581 ret = RhodeCodeUi.query()\
582 ret = RhodeCodeUi.query()\
582 .options(FromCache("sql_cache_short", "repository_repo_ui")).all()
583 .options(FromCache("sql_cache_short", "repository_repo_ui")).all()
583
584
584 hg_ui = ret
585 hg_ui = ret
585 for ui_ in hg_ui:
586 for ui_ in hg_ui:
586 if ui_.ui_active:
587 if ui_.ui_active:
587 log.debug('settings ui from db[%s]%s:%s', ui_.ui_section,
588 log.debug('settings ui from db[%s]%s:%s', ui_.ui_section,
588 ui_.ui_key, ui_.ui_value)
589 ui_.ui_key, ui_.ui_value)
589 baseui.setconfig(ui_.ui_section, ui_.ui_key, ui_.ui_value)
590 baseui.setconfig(ui_.ui_section, ui_.ui_key, ui_.ui_value)
590
591
591 return baseui
592 return baseui
592
593
593 @classmethod
594 @classmethod
594 def is_valid(cls, repo_name):
595 def is_valid(cls, repo_name):
595 """
596 """
596 returns True if given repo name is a valid filesystem repository
597 returns True if given repo name is a valid filesystem repository
597
598
598 :param cls:
599 :param cls:
599 :param repo_name:
600 :param repo_name:
600 """
601 """
601 from rhodecode.lib.utils import is_valid_repo
602 from rhodecode.lib.utils import is_valid_repo
602
603
603 return is_valid_repo(repo_name, cls.base_path())
604 return is_valid_repo(repo_name, cls.base_path())
604
605
605 #==========================================================================
606 #==========================================================================
606 # SCM PROPERTIES
607 # SCM PROPERTIES
607 #==========================================================================
608 #==========================================================================
608
609
609 def get_changeset(self, rev):
610 def get_changeset(self, rev):
610 return get_changeset_safe(self.scm_instance, rev)
611 return get_changeset_safe(self.scm_instance, rev)
611
612
612 @property
613 @property
613 def tip(self):
614 def tip(self):
614 return self.get_changeset('tip')
615 return self.get_changeset('tip')
615
616
616 @property
617 @property
617 def author(self):
618 def author(self):
618 return self.tip.author
619 return self.tip.author
619
620
620 @property
621 @property
621 def last_change(self):
622 def last_change(self):
622 return self.scm_instance.last_change
623 return self.scm_instance.last_change
623
624
624 def comments(self, revisions=None):
625 def comments(self, revisions=None):
625 """
626 """
626 Returns comments for this repository grouped by revisions
627 Returns comments for this repository grouped by revisions
627
628
628 :param revisions: filter query by revisions only
629 :param revisions: filter query by revisions only
629 """
630 """
630 cmts = ChangesetComment.query()\
631 cmts = ChangesetComment.query()\
631 .filter(ChangesetComment.repo == self)
632 .filter(ChangesetComment.repo == self)
632 if revisions:
633 if revisions:
633 cmts = cmts.filter(ChangesetComment.revision.in_(revisions))
634 cmts = cmts.filter(ChangesetComment.revision.in_(revisions))
634 grouped = defaultdict(list)
635 grouped = defaultdict(list)
635 for cmt in cmts.all():
636 for cmt in cmts.all():
636 grouped[cmt.revision].append(cmt)
637 grouped[cmt.revision].append(cmt)
637 return grouped
638 return grouped
638
639
639 #==========================================================================
640 #==========================================================================
640 # SCM CACHE INSTANCE
641 # SCM CACHE INSTANCE
641 #==========================================================================
642 #==========================================================================
642
643
643 @property
644 @property
644 def invalidate(self):
645 def invalidate(self):
645 return CacheInvalidation.invalidate(self.repo_name)
646 return CacheInvalidation.invalidate(self.repo_name)
646
647
647 def set_invalidate(self):
648 def set_invalidate(self):
648 """
649 """
649 set a cache for invalidation for this instance
650 set a cache for invalidation for this instance
650 """
651 """
651 CacheInvalidation.set_invalidate(self.repo_name)
652 CacheInvalidation.set_invalidate(self.repo_name)
652
653
653 @LazyProperty
654 @LazyProperty
654 def scm_instance(self):
655 def scm_instance(self):
655 return self.__get_instance()
656 return self.__get_instance()
656
657
657 @property
658 @property
658 def scm_instance_cached(self):
659 def scm_instance_cached(self):
659 @cache_region('long_term')
660 @cache_region('long_term')
660 def _c(repo_name):
661 def _c(repo_name):
661 return self.__get_instance()
662 return self.__get_instance()
662 rn = self.repo_name
663 rn = self.repo_name
663 log.debug('Getting cached instance of repo')
664 log.debug('Getting cached instance of repo')
664 inv = self.invalidate
665 inv = self.invalidate
665 if inv is not None:
666 if inv is not None:
666 region_invalidate(_c, None, rn)
667 region_invalidate(_c, None, rn)
667 # update our cache
668 # update our cache
668 CacheInvalidation.set_valid(inv.cache_key)
669 CacheInvalidation.set_valid(inv.cache_key)
669 return _c(rn)
670 return _c(rn)
670
671
671 def __get_instance(self):
672 def __get_instance(self):
672 repo_full_path = self.repo_full_path
673 repo_full_path = self.repo_full_path
673 try:
674 try:
674 alias = get_scm(repo_full_path)[0]
675 alias = get_scm(repo_full_path)[0]
675 log.debug('Creating instance of %s repository' % alias)
676 log.debug('Creating instance of %s repository' % alias)
676 backend = get_backend(alias)
677 backend = get_backend(alias)
677 except VCSError:
678 except VCSError:
678 log.error(traceback.format_exc())
679 log.error(traceback.format_exc())
679 log.error('Perhaps this repository is in db and not in '
680 log.error('Perhaps this repository is in db and not in '
680 'filesystem run rescan repositories with '
681 'filesystem run rescan repositories with '
681 '"destroy old data " option from admin panel')
682 '"destroy old data " option from admin panel')
682 return
683 return
683
684
684 if alias == 'hg':
685 if alias == 'hg':
685
686
686 repo = backend(safe_str(repo_full_path), create=False,
687 repo = backend(safe_str(repo_full_path), create=False,
687 baseui=self._ui)
688 baseui=self._ui)
688 # skip hidden web repository
689 # skip hidden web repository
689 if repo._get_hidden():
690 if repo._get_hidden():
690 return
691 return
691 else:
692 else:
692 repo = backend(repo_full_path, create=False)
693 repo = backend(repo_full_path, create=False)
693
694
694 return repo
695 return repo
695
696
696
697
697 class RepoGroup(Base, BaseModel):
698 class RepoGroup(Base, BaseModel):
698 __tablename__ = 'groups'
699 __tablename__ = 'groups'
699 __table_args__ = (
700 __table_args__ = (
700 UniqueConstraint('group_name', 'group_parent_id'),
701 UniqueConstraint('group_name', 'group_parent_id'),
701 CheckConstraint('group_id != group_parent_id'),
702 CheckConstraint('group_id != group_parent_id'),
702 {'extend_existing': True},
703 {'extend_existing': True},
703 )
704 )
704 __mapper_args__ = {'order_by': 'group_name'}
705 __mapper_args__ = {'order_by': 'group_name'}
705
706
706 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
707 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
707 group_name = Column("group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
708 group_name = Column("group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
708 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
709 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
709 group_description = Column("group_description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
710 group_description = Column("group_description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
710
711
711 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
712 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
712 users_group_to_perm = relationship('UsersGroupRepoGroupToPerm', cascade='all')
713 users_group_to_perm = relationship('UsersGroupRepoGroupToPerm', cascade='all')
713
714
714 parent_group = relationship('RepoGroup', remote_side=group_id)
715 parent_group = relationship('RepoGroup', remote_side=group_id)
715
716
716 def __init__(self, group_name='', parent_group=None):
717 def __init__(self, group_name='', parent_group=None):
717 self.group_name = group_name
718 self.group_name = group_name
718 self.parent_group = parent_group
719 self.parent_group = parent_group
719
720
720 def __repr__(self):
721 def __repr__(self):
721 return "<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
722 return "<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
722 self.group_name)
723 self.group_name)
723
724
724 @classmethod
725 @classmethod
725 def groups_choices(cls):
726 def groups_choices(cls):
726 from webhelpers.html import literal as _literal
727 from webhelpers.html import literal as _literal
727 repo_groups = [('', '')]
728 repo_groups = [('', '')]
728 sep = ' &raquo; '
729 sep = ' &raquo; '
729 _name = lambda k: _literal(sep.join(k))
730 _name = lambda k: _literal(sep.join(k))
730
731
731 repo_groups.extend([(x.group_id, _name(x.full_path_splitted))
732 repo_groups.extend([(x.group_id, _name(x.full_path_splitted))
732 for x in cls.query().all()])
733 for x in cls.query().all()])
733
734
734 repo_groups = sorted(repo_groups, key=lambda t: t[1].split(sep)[0])
735 repo_groups = sorted(repo_groups, key=lambda t: t[1].split(sep)[0])
735 return repo_groups
736 return repo_groups
736
737
737 @classmethod
738 @classmethod
738 def url_sep(cls):
739 def url_sep(cls):
739 return '/'
740 return '/'
740
741
741 @classmethod
742 @classmethod
742 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
743 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
743 if case_insensitive:
744 if case_insensitive:
744 gr = cls.query()\
745 gr = cls.query()\
745 .filter(cls.group_name.ilike(group_name))
746 .filter(cls.group_name.ilike(group_name))
746 else:
747 else:
747 gr = cls.query()\
748 gr = cls.query()\
748 .filter(cls.group_name == group_name)
749 .filter(cls.group_name == group_name)
749 if cache:
750 if cache:
750 gr = gr.options(FromCache("sql_cache_short",
751 gr = gr.options(FromCache("sql_cache_short",
751 "get_group_%s" % group_name))
752 "get_group_%s" % group_name))
752 return gr.scalar()
753 return gr.scalar()
753
754
754 @property
755 @property
755 def parents(self):
756 def parents(self):
756 parents_recursion_limit = 5
757 parents_recursion_limit = 5
757 groups = []
758 groups = []
758 if self.parent_group is None:
759 if self.parent_group is None:
759 return groups
760 return groups
760 cur_gr = self.parent_group
761 cur_gr = self.parent_group
761 groups.insert(0, cur_gr)
762 groups.insert(0, cur_gr)
762 cnt = 0
763 cnt = 0
763 while 1:
764 while 1:
764 cnt += 1
765 cnt += 1
765 gr = getattr(cur_gr, 'parent_group', None)
766 gr = getattr(cur_gr, 'parent_group', None)
766 cur_gr = cur_gr.parent_group
767 cur_gr = cur_gr.parent_group
767 if gr is None:
768 if gr is None:
768 break
769 break
769 if cnt == parents_recursion_limit:
770 if cnt == parents_recursion_limit:
770 # this will prevent accidental infinit loops
771 # this will prevent accidental infinit loops
771 log.error('group nested more than %s' %
772 log.error('group nested more than %s' %
772 parents_recursion_limit)
773 parents_recursion_limit)
773 break
774 break
774
775
775 groups.insert(0, gr)
776 groups.insert(0, gr)
776 return groups
777 return groups
777
778
778 @property
779 @property
779 def children(self):
780 def children(self):
780 return RepoGroup.query().filter(RepoGroup.parent_group == self)
781 return RepoGroup.query().filter(RepoGroup.parent_group == self)
781
782
782 @property
783 @property
783 def name(self):
784 def name(self):
784 return self.group_name.split(RepoGroup.url_sep())[-1]
785 return self.group_name.split(RepoGroup.url_sep())[-1]
785
786
786 @property
787 @property
787 def full_path(self):
788 def full_path(self):
788 return self.group_name
789 return self.group_name
789
790
790 @property
791 @property
791 def full_path_splitted(self):
792 def full_path_splitted(self):
792 return self.group_name.split(RepoGroup.url_sep())
793 return self.group_name.split(RepoGroup.url_sep())
793
794
794 @property
795 @property
795 def repositories(self):
796 def repositories(self):
796 return Repository.query().filter(Repository.group == self)
797 return Repository.query().filter(Repository.group == self)
797
798
798 @property
799 @property
799 def repositories_recursive_count(self):
800 def repositories_recursive_count(self):
800 cnt = self.repositories.count()
801 cnt = self.repositories.count()
801
802
802 def children_count(group):
803 def children_count(group):
803 cnt = 0
804 cnt = 0
804 for child in group.children:
805 for child in group.children:
805 cnt += child.repositories.count()
806 cnt += child.repositories.count()
806 cnt += children_count(child)
807 cnt += children_count(child)
807 return cnt
808 return cnt
808
809
809 return cnt + children_count(self)
810 return cnt + children_count(self)
810
811
811 def get_new_name(self, group_name):
812 def get_new_name(self, group_name):
812 """
813 """
813 returns new full group name based on parent and new name
814 returns new full group name based on parent and new name
814
815
815 :param group_name:
816 :param group_name:
816 """
817 """
817 path_prefix = (self.parent_group.full_path_splitted if
818 path_prefix = (self.parent_group.full_path_splitted if
818 self.parent_group else [])
819 self.parent_group else [])
819 return RepoGroup.url_sep().join(path_prefix + [group_name])
820 return RepoGroup.url_sep().join(path_prefix + [group_name])
820
821
821
822
822 class Permission(Base, BaseModel):
823 class Permission(Base, BaseModel):
823 __tablename__ = 'permissions'
824 __tablename__ = 'permissions'
824 __table_args__ = {'extend_existing': True}
825 __table_args__ = {'extend_existing': True}
825 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
826 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
826 permission_name = Column("permission_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
827 permission_name = Column("permission_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
827 permission_longname = Column("permission_longname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
828 permission_longname = Column("permission_longname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
828
829
829 def __repr__(self):
830 def __repr__(self):
830 return "<%s('%s:%s')>" % (
831 return "<%s('%s:%s')>" % (
831 self.__class__.__name__, self.permission_id, self.permission_name
832 self.__class__.__name__, self.permission_id, self.permission_name
832 )
833 )
833
834
834 @classmethod
835 @classmethod
835 def get_by_key(cls, key):
836 def get_by_key(cls, key):
836 return cls.query().filter(cls.permission_name == key).scalar()
837 return cls.query().filter(cls.permission_name == key).scalar()
837
838
838 @classmethod
839 @classmethod
839 def get_default_perms(cls, default_user_id):
840 def get_default_perms(cls, default_user_id):
840 q = Session.query(UserRepoToPerm, Repository, cls)\
841 q = Session.query(UserRepoToPerm, Repository, cls)\
841 .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
842 .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
842 .join((cls, UserRepoToPerm.permission_id == cls.permission_id))\
843 .join((cls, UserRepoToPerm.permission_id == cls.permission_id))\
843 .filter(UserRepoToPerm.user_id == default_user_id)
844 .filter(UserRepoToPerm.user_id == default_user_id)
844
845
845 return q.all()
846 return q.all()
846
847
847 @classmethod
848 @classmethod
848 def get_default_group_perms(cls, default_user_id):
849 def get_default_group_perms(cls, default_user_id):
849 q = Session.query(UserRepoGroupToPerm, RepoGroup, cls)\
850 q = Session.query(UserRepoGroupToPerm, RepoGroup, cls)\
850 .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
851 .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
851 .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id))\
852 .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id))\
852 .filter(UserRepoGroupToPerm.user_id == default_user_id)
853 .filter(UserRepoGroupToPerm.user_id == default_user_id)
853
854
854 return q.all()
855 return q.all()
855
856
856
857
857 class UserRepoToPerm(Base, BaseModel):
858 class UserRepoToPerm(Base, BaseModel):
858 __tablename__ = 'repo_to_perm'
859 __tablename__ = 'repo_to_perm'
859 __table_args__ = (
860 __table_args__ = (
860 UniqueConstraint('user_id', 'repository_id', 'permission_id'),
861 UniqueConstraint('user_id', 'repository_id', 'permission_id'),
861 {'extend_existing': True}
862 {'extend_existing': True}
862 )
863 )
863 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
864 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
864 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
865 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
865 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
866 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
866 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
867 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
867
868
868 user = relationship('User')
869 user = relationship('User')
869 repository = relationship('Repository')
870 repository = relationship('Repository')
870 permission = relationship('Permission')
871 permission = relationship('Permission')
871
872
872 @classmethod
873 @classmethod
873 def create(cls, user, repository, permission):
874 def create(cls, user, repository, permission):
874 n = cls()
875 n = cls()
875 n.user = user
876 n.user = user
876 n.repository = repository
877 n.repository = repository
877 n.permission = permission
878 n.permission = permission
878 Session.add(n)
879 Session.add(n)
879 return n
880 return n
880
881
881 def __repr__(self):
882 def __repr__(self):
882 return '<user:%s => %s >' % (self.user, self.repository)
883 return '<user:%s => %s >' % (self.user, self.repository)
883
884
884
885
885 class UserToPerm(Base, BaseModel):
886 class UserToPerm(Base, BaseModel):
886 __tablename__ = 'user_to_perm'
887 __tablename__ = 'user_to_perm'
887 __table_args__ = (
888 __table_args__ = (
888 UniqueConstraint('user_id', 'permission_id'),
889 UniqueConstraint('user_id', 'permission_id'),
889 {'extend_existing': True}
890 {'extend_existing': True}
890 )
891 )
891 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
892 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
892 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
893 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
893 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
894 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
894
895
895 user = relationship('User')
896 user = relationship('User')
896 permission = relationship('Permission', lazy='joined')
897 permission = relationship('Permission', lazy='joined')
897
898
898
899
899 class UsersGroupRepoToPerm(Base, BaseModel):
900 class UsersGroupRepoToPerm(Base, BaseModel):
900 __tablename__ = 'users_group_repo_to_perm'
901 __tablename__ = 'users_group_repo_to_perm'
901 __table_args__ = (
902 __table_args__ = (
902 UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
903 UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
903 {'extend_existing': True}
904 {'extend_existing': True}
904 )
905 )
905 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
906 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
906 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
907 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
907 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
908 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
908 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
909 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
909
910
910 users_group = relationship('UsersGroup')
911 users_group = relationship('UsersGroup')
911 permission = relationship('Permission')
912 permission = relationship('Permission')
912 repository = relationship('Repository')
913 repository = relationship('Repository')
913
914
914 @classmethod
915 @classmethod
915 def create(cls, users_group, repository, permission):
916 def create(cls, users_group, repository, permission):
916 n = cls()
917 n = cls()
917 n.users_group = users_group
918 n.users_group = users_group
918 n.repository = repository
919 n.repository = repository
919 n.permission = permission
920 n.permission = permission
920 Session.add(n)
921 Session.add(n)
921 return n
922 return n
922
923
923 def __repr__(self):
924 def __repr__(self):
924 return '<userGroup:%s => %s >' % (self.users_group, self.repository)
925 return '<userGroup:%s => %s >' % (self.users_group, self.repository)
925
926
926
927
927 class UsersGroupToPerm(Base, BaseModel):
928 class UsersGroupToPerm(Base, BaseModel):
928 __tablename__ = 'users_group_to_perm'
929 __tablename__ = 'users_group_to_perm'
929 __table_args__ = (
930 __table_args__ = (
930 UniqueConstraint('users_group_id', 'permission_id',),
931 UniqueConstraint('users_group_id', 'permission_id',),
931 {'extend_existing': True}
932 {'extend_existing': True}
932 )
933 )
933 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
934 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
934 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
935 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
935 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
936 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
936
937
937 users_group = relationship('UsersGroup')
938 users_group = relationship('UsersGroup')
938 permission = relationship('Permission')
939 permission = relationship('Permission')
939
940
940
941
941 class UserRepoGroupToPerm(Base, BaseModel):
942 class UserRepoGroupToPerm(Base, BaseModel):
942 __tablename__ = 'user_repo_group_to_perm'
943 __tablename__ = 'user_repo_group_to_perm'
943 __table_args__ = (
944 __table_args__ = (
944 UniqueConstraint('user_id', 'group_id', 'permission_id'),
945 UniqueConstraint('user_id', 'group_id', 'permission_id'),
945 {'extend_existing': True}
946 {'extend_existing': True}
946 )
947 )
947
948
948 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
949 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
949 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
950 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
950 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
951 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
951 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
952 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
952
953
953 user = relationship('User')
954 user = relationship('User')
954 group = relationship('RepoGroup')
955 group = relationship('RepoGroup')
955 permission = relationship('Permission')
956 permission = relationship('Permission')
956
957
957
958
958 class UsersGroupRepoGroupToPerm(Base, BaseModel):
959 class UsersGroupRepoGroupToPerm(Base, BaseModel):
959 __tablename__ = 'users_group_repo_group_to_perm'
960 __tablename__ = 'users_group_repo_group_to_perm'
960 __table_args__ = (
961 __table_args__ = (
961 UniqueConstraint('users_group_id', 'group_id'),
962 UniqueConstraint('users_group_id', 'group_id'),
962 {'extend_existing': True}
963 {'extend_existing': True}
963 )
964 )
964
965
965 users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
966 users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
966 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
967 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
967 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
968 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
968 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
969 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
969
970
970 users_group = relationship('UsersGroup')
971 users_group = relationship('UsersGroup')
971 permission = relationship('Permission')
972 permission = relationship('Permission')
972 group = relationship('RepoGroup')
973 group = relationship('RepoGroup')
973
974
974
975
975 class Statistics(Base, BaseModel):
976 class Statistics(Base, BaseModel):
976 __tablename__ = 'statistics'
977 __tablename__ = 'statistics'
977 __table_args__ = (UniqueConstraint('repository_id'), {'extend_existing': True})
978 __table_args__ = (UniqueConstraint('repository_id'), {'extend_existing': True})
978 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
979 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
979 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
980 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
980 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
981 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
981 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
982 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
982 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
983 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
983 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
984 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
984
985
985 repository = relationship('Repository', single_parent=True)
986 repository = relationship('Repository', single_parent=True)
986
987
987
988
988 class UserFollowing(Base, BaseModel):
989 class UserFollowing(Base, BaseModel):
989 __tablename__ = 'user_followings'
990 __tablename__ = 'user_followings'
990 __table_args__ = (
991 __table_args__ = (
991 UniqueConstraint('user_id', 'follows_repository_id'),
992 UniqueConstraint('user_id', 'follows_repository_id'),
992 UniqueConstraint('user_id', 'follows_user_id'),
993 UniqueConstraint('user_id', 'follows_user_id'),
993 {'extend_existing': True}
994 {'extend_existing': True}
994 )
995 )
995
996
996 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
997 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
997 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
998 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
998 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
999 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
999 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
1000 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
1000 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
1001 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
1001
1002
1002 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
1003 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
1003
1004
1004 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
1005 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
1005 follows_repository = relationship('Repository', order_by='Repository.repo_name')
1006 follows_repository = relationship('Repository', order_by='Repository.repo_name')
1006
1007
1007 @classmethod
1008 @classmethod
1008 def get_repo_followers(cls, repo_id):
1009 def get_repo_followers(cls, repo_id):
1009 return cls.query().filter(cls.follows_repo_id == repo_id)
1010 return cls.query().filter(cls.follows_repo_id == repo_id)
1010
1011
1011
1012
1012 class CacheInvalidation(Base, BaseModel):
1013 class CacheInvalidation(Base, BaseModel):
1013 __tablename__ = 'cache_invalidation'
1014 __tablename__ = 'cache_invalidation'
1014 __table_args__ = (UniqueConstraint('cache_key'), {'extend_existing': True})
1015 __table_args__ = (UniqueConstraint('cache_key'), {'extend_existing': True})
1015 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1016 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1016 cache_key = Column("cache_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1017 cache_key = Column("cache_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1017 cache_args = Column("cache_args", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1018 cache_args = Column("cache_args", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1018 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
1019 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
1019
1020
1020 def __init__(self, cache_key, cache_args=''):
1021 def __init__(self, cache_key, cache_args=''):
1021 self.cache_key = cache_key
1022 self.cache_key = cache_key
1022 self.cache_args = cache_args
1023 self.cache_args = cache_args
1023 self.cache_active = False
1024 self.cache_active = False
1024
1025
1025 def __repr__(self):
1026 def __repr__(self):
1026 return "<%s('%s:%s')>" % (self.__class__.__name__,
1027 return "<%s('%s:%s')>" % (self.__class__.__name__,
1027 self.cache_id, self.cache_key)
1028 self.cache_id, self.cache_key)
1028
1029
1029 @classmethod
1030 @classmethod
1031 def _get_key(cls, key):
1032 """
1033 Wrapper for generating a key
1034
1035 :param key:
1036 """
1037 return "%s" % (key)
1038
1039 @classmethod
1040 def get_by_key(cls, key):
1041 return cls.query().filter(cls.cache_key == key).scalar()
1042
1043 @classmethod
1030 def invalidate(cls, key):
1044 def invalidate(cls, key):
1031 """
1045 """
1032 Returns Invalidation object if this given key should be invalidated
1046 Returns Invalidation object if this given key should be invalidated
1033 None otherwise. `cache_active = False` means that this cache
1047 None otherwise. `cache_active = False` means that this cache
1034 state is not valid and needs to be invalidated
1048 state is not valid and needs to be invalidated
1035
1049
1036 :param key:
1050 :param key:
1037 """
1051 """
1038 return cls.query()\
1052 return cls.query()\
1039 .filter(CacheInvalidation.cache_key == key)\
1053 .filter(CacheInvalidation.cache_key == key)\
1040 .filter(CacheInvalidation.cache_active == False)\
1054 .filter(CacheInvalidation.cache_active == False)\
1041 .scalar()
1055 .scalar()
1042
1056
1043 @classmethod
1057 @classmethod
1044 def set_invalidate(cls, key):
1058 def set_invalidate(cls, key):
1045 """
1059 """
1046 Mark this Cache key for invalidation
1060 Mark this Cache key for invalidation
1047
1061
1048 :param key:
1062 :param key:
1049 """
1063 """
1050
1064
1051 log.debug('marking %s for invalidation' % key)
1065 log.debug('marking %s for invalidation' % key)
1052 inv_obj = Session.query(cls)\
1066 inv_obj = Session.query(cls)\
1053 .filter(cls.cache_key == key).scalar()
1067 .filter(cls.cache_key == key).scalar()
1054 if inv_obj:
1068 if inv_obj:
1055 inv_obj.cache_active = False
1069 inv_obj.cache_active = False
1056 else:
1070 else:
1057 log.debug('cache key not found in invalidation db -> creating one')
1071 log.debug('cache key not found in invalidation db -> creating one')
1058 inv_obj = CacheInvalidation(key)
1072 inv_obj = CacheInvalidation(key)
1059
1073
1060 try:
1074 try:
1061 Session.add(inv_obj)
1075 Session.add(inv_obj)
1062 Session.commit()
1076 Session.commit()
1063 except Exception:
1077 except Exception:
1064 log.error(traceback.format_exc())
1078 log.error(traceback.format_exc())
1065 Session.rollback()
1079 Session.rollback()
1066
1080
1067 @classmethod
1081 @classmethod
1068 def set_valid(cls, key):
1082 def set_valid(cls, key):
1069 """
1083 """
1070 Mark this cache key as active and currently cached
1084 Mark this cache key as active and currently cached
1071
1085
1072 :param key:
1086 :param key:
1073 """
1087 """
1074 inv_obj = CacheInvalidation.query()\
1088 inv_obj = cls.get_by_key(key)
1075 .filter(CacheInvalidation.cache_key == key).scalar()
1076 inv_obj.cache_active = True
1089 inv_obj.cache_active = True
1077 Session.add(inv_obj)
1090 Session.add(inv_obj)
1078 Session.commit()
1091 Session.commit()
1079
1092
1080
1093
1081 class ChangesetComment(Base, BaseModel):
1094 class ChangesetComment(Base, BaseModel):
1082 __tablename__ = 'changeset_comments'
1095 __tablename__ = 'changeset_comments'
1083 __table_args__ = ({'extend_existing': True},)
1096 __table_args__ = ({'extend_existing': True},)
1084 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
1097 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
1085 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1098 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1086 revision = Column('revision', String(40), nullable=False)
1099 revision = Column('revision', String(40), nullable=False)
1087 line_no = Column('line_no', Unicode(10), nullable=True)
1100 line_no = Column('line_no', Unicode(10), nullable=True)
1088 f_path = Column('f_path', Unicode(1000), nullable=True)
1101 f_path = Column('f_path', Unicode(1000), nullable=True)
1089 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
1102 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
1090 text = Column('text', Unicode(25000), nullable=False)
1103 text = Column('text', Unicode(25000), nullable=False)
1091 modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
1104 modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
1092
1105
1093 author = relationship('User', lazy='joined')
1106 author = relationship('User', lazy='joined')
1094 repo = relationship('Repository')
1107 repo = relationship('Repository')
1095
1108
1096 @classmethod
1109 @classmethod
1097 def get_users(cls, revision):
1110 def get_users(cls, revision):
1098 """
1111 """
1099 Returns user associated with this changesetComment. ie those
1112 Returns user associated with this changesetComment. ie those
1100 who actually commented
1113 who actually commented
1101
1114
1102 :param cls:
1115 :param cls:
1103 :param revision:
1116 :param revision:
1104 """
1117 """
1105 return Session.query(User)\
1118 return Session.query(User)\
1106 .filter(cls.revision == revision)\
1119 .filter(cls.revision == revision)\
1107 .join(ChangesetComment.author).all()
1120 .join(ChangesetComment.author).all()
1108
1121
1109
1122
1110 class Notification(Base, BaseModel):
1123 class Notification(Base, BaseModel):
1111 __tablename__ = 'notifications'
1124 __tablename__ = 'notifications'
1112 __table_args__ = ({'extend_existing': True},)
1125 __table_args__ = ({'extend_existing': True},)
1113
1126
1114 TYPE_CHANGESET_COMMENT = u'cs_comment'
1127 TYPE_CHANGESET_COMMENT = u'cs_comment'
1115 TYPE_MESSAGE = u'message'
1128 TYPE_MESSAGE = u'message'
1116 TYPE_MENTION = u'mention'
1129 TYPE_MENTION = u'mention'
1117 TYPE_REGISTRATION = u'registration'
1130 TYPE_REGISTRATION = u'registration'
1118
1131
1119 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
1132 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
1120 subject = Column('subject', Unicode(512), nullable=True)
1133 subject = Column('subject', Unicode(512), nullable=True)
1121 body = Column('body', Unicode(50000), nullable=True)
1134 body = Column('body', Unicode(50000), nullable=True)
1122 created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
1135 created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
1123 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1136 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1124 type_ = Column('type', Unicode(256))
1137 type_ = Column('type', Unicode(256))
1125
1138
1126 created_by_user = relationship('User')
1139 created_by_user = relationship('User')
1127 notifications_to_users = relationship('UserNotification', lazy='joined',
1140 notifications_to_users = relationship('UserNotification', lazy='joined',
1128 cascade="all, delete, delete-orphan")
1141 cascade="all, delete, delete-orphan")
1129
1142
1130 @property
1143 @property
1131 def recipients(self):
1144 def recipients(self):
1132 return [x.user for x in UserNotification.query()\
1145 return [x.user for x in UserNotification.query()\
1133 .filter(UserNotification.notification == self).all()]
1146 .filter(UserNotification.notification == self).all()]
1134
1147
1135 @classmethod
1148 @classmethod
1136 def create(cls, created_by, subject, body, recipients, type_=None):
1149 def create(cls, created_by, subject, body, recipients, type_=None):
1137 if type_ is None:
1150 if type_ is None:
1138 type_ = Notification.TYPE_MESSAGE
1151 type_ = Notification.TYPE_MESSAGE
1139
1152
1140 notification = cls()
1153 notification = cls()
1141 notification.created_by_user = created_by
1154 notification.created_by_user = created_by
1142 notification.subject = subject
1155 notification.subject = subject
1143 notification.body = body
1156 notification.body = body
1144 notification.type_ = type_
1157 notification.type_ = type_
1145 notification.created_on = datetime.datetime.now()
1158 notification.created_on = datetime.datetime.now()
1146
1159
1147 for u in recipients:
1160 for u in recipients:
1148 assoc = UserNotification()
1161 assoc = UserNotification()
1149 assoc.notification = notification
1162 assoc.notification = notification
1150 u.notifications.append(assoc)
1163 u.notifications.append(assoc)
1151 Session.add(notification)
1164 Session.add(notification)
1152 return notification
1165 return notification
1153
1166
1154 @property
1167 @property
1155 def description(self):
1168 def description(self):
1156 from rhodecode.model.notification import NotificationModel
1169 from rhodecode.model.notification import NotificationModel
1157 return NotificationModel().make_description(self)
1170 return NotificationModel().make_description(self)
1158
1171
1159
1172
1160 class UserNotification(Base, BaseModel):
1173 class UserNotification(Base, BaseModel):
1161 __tablename__ = 'user_to_notification'
1174 __tablename__ = 'user_to_notification'
1162 __table_args__ = (
1175 __table_args__ = (
1163 UniqueConstraint('user_id', 'notification_id'),
1176 UniqueConstraint('user_id', 'notification_id'),
1164 {'extend_existing': True}
1177 {'extend_existing': True}
1165 )
1178 )
1166 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
1179 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
1167 notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
1180 notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
1168 read = Column('read', Boolean, default=False)
1181 read = Column('read', Boolean, default=False)
1169 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
1182 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
1170
1183
1171 user = relationship('User', lazy="joined")
1184 user = relationship('User', lazy="joined")
1172 notification = relationship('Notification', lazy="joined",
1185 notification = relationship('Notification', lazy="joined",
1173 order_by=lambda: Notification.created_on.desc(),)
1186 order_by=lambda: Notification.created_on.desc(),)
1174
1187
1175 def mark_as_read(self):
1188 def mark_as_read(self):
1176 self.read = True
1189 self.read = True
1177 Session.add(self)
1190 Session.add(self)
1178
1191
1179
1192
1180 class DbMigrateVersion(Base, BaseModel):
1193 class DbMigrateVersion(Base, BaseModel):
1181 __tablename__ = 'db_migrate_version'
1194 __tablename__ = 'db_migrate_version'
1182 __table_args__ = {'extend_existing': True}
1195 __table_args__ = {'extend_existing': True}
1183 repository_id = Column('repository_id', String(250), primary_key=True)
1196 repository_id = Column('repository_id', String(250), primary_key=True)
1184 repository_path = Column('repository_path', Text)
1197 repository_path = Column('repository_path', Text)
1185 version = Column('version', Integer)
1198 version = Column('version', Integer)
General Comments 0
You need to be logged in to leave comments. Login now