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