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