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