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