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