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